mirror of
https://github.com/zadam/trilium.git
synced 2025-11-01 19:05:59 +01:00
Compare commits
282 Commits
v0.59.0-be
...
v0.60.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e22f77eae7 | ||
|
|
3223e76787 | ||
|
|
74400dad97 | ||
|
|
1b68adf3e4 | ||
|
|
bea39f37ee | ||
|
|
6548149107 | ||
|
|
6015a067ec | ||
|
|
4a1ecd906b | ||
|
|
004cfe1965 | ||
|
|
2bdd538d7d | ||
|
|
6e69cafe54 | ||
|
|
8bc84cfaf6 | ||
|
|
282d135f0f | ||
|
|
d3bf325f19 | ||
|
|
c4f69fd9cb | ||
|
|
af67cf64b1 | ||
|
|
095da691a4 | ||
|
|
7e71029d1c | ||
|
|
e47c3a27b0 | ||
|
|
ced99f8ac8 | ||
|
|
0c4492bcd0 | ||
|
|
d9359c7c55 | ||
|
|
86a080e7ec | ||
|
|
758dba9ba5 | ||
|
|
ae42e0efc7 | ||
|
|
b5cfc28912 | ||
|
|
c802bf7d8b | ||
|
|
9e5a02094c | ||
|
|
58253567cd | ||
|
|
a6ade790c6 | ||
|
|
a9dae7823f | ||
|
|
d26a0fae17 | ||
|
|
375dba3264 | ||
|
|
74044754e2 | ||
|
|
64aed9b462 | ||
|
|
5428cafa50 | ||
|
|
735852b3c1 | ||
|
|
2a39906993 | ||
|
|
e1b67e20ec | ||
|
|
1a2beb941e | ||
|
|
01b2887b36 | ||
|
|
5286d4a97c | ||
|
|
bf6106f4dc | ||
|
|
82efc92413 | ||
|
|
34481df2e7 | ||
|
|
ad4631018a | ||
|
|
ef89eede17 | ||
|
|
6878877acd | ||
|
|
611a983461 | ||
|
|
9d49264258 | ||
|
|
6098d62dcc | ||
|
|
580ceec6b3 | ||
|
|
79dca12274 | ||
|
|
66c25e7f29 | ||
|
|
dc4983a013 | ||
|
|
039959a48b | ||
|
|
63be25f5bb | ||
|
|
ce7489049f | ||
|
|
b3d5938665 | ||
|
|
7fc2824325 | ||
|
|
0728f540ab | ||
|
|
4913a5a5fa | ||
|
|
14dd2b8827 | ||
|
|
4e9e7eba48 | ||
|
|
f3bc604516 | ||
|
|
bd278e291a | ||
|
|
074820dae5 | ||
|
|
1089e84f56 | ||
|
|
ed3d81ce62 | ||
|
|
57aa0a0fe1 | ||
|
|
88a961180f | ||
|
|
bd8429a0ba | ||
|
|
da348075e8 | ||
|
|
d24d3af87d | ||
|
|
085c0e76ca | ||
|
|
d7d98b29a7 | ||
|
|
cb3b03537c | ||
|
|
7c7bea5e3a | ||
|
|
9fc474504b | ||
|
|
412fd105c9 | ||
|
|
470a0c7b21 | ||
|
|
9968cba348 | ||
|
|
aee520a209 | ||
|
|
cf4201b084 | ||
|
|
6089a369e3 | ||
|
|
092db03729 | ||
|
|
239c14a5df | ||
|
|
0518cdbe8e | ||
|
|
4849dacd52 | ||
|
|
7cf47520d4 | ||
|
|
8eb0a4e1cb | ||
|
|
ad2a7a2da3 | ||
|
|
6a9aa5eeda | ||
|
|
04524ae8e4 | ||
|
|
04caba9f5b | ||
|
|
cc1f831a6a | ||
|
|
331d280075 | ||
|
|
46ed61d38a | ||
|
|
c4a2ff5fa1 | ||
|
|
5676ff9b2e | ||
|
|
aa8c0fdad8 | ||
|
|
d09132dd60 | ||
|
|
ec662d01d0 | ||
|
|
ad0b98e2a1 | ||
|
|
3cafad3bf4 | ||
|
|
fbea3ed94f | ||
|
|
0ab18e3069 | ||
|
|
4aeecfdfa9 | ||
|
|
79d4dcf5f1 | ||
|
|
26a6ef8c03 | ||
|
|
bb9631476e | ||
|
|
386e8dd32e | ||
|
|
61616f708f | ||
|
|
8ce499e958 | ||
|
|
22587ee6b5 | ||
|
|
5ea8226996 | ||
|
|
bb8fd2b054 | ||
|
|
c9aab9b479 | ||
|
|
53c87f3d25 | ||
|
|
4f1fafdf75 | ||
|
|
0896000fcd | ||
|
|
e007aba067 | ||
|
|
a6eda2479f | ||
|
|
eff567ee48 | ||
|
|
d3c2c314ac | ||
|
|
89681977b5 | ||
|
|
e10a7ea9a6 | ||
|
|
c3c6d73bb2 | ||
|
|
e24d5a6f83 | ||
|
|
8725f7cfb2 | ||
|
|
83d8908ee8 | ||
|
|
af9ef83742 | ||
|
|
3eafdadd1f | ||
|
|
1d3272e9f8 | ||
|
|
447b8f0f0c | ||
|
|
aaf6e3bace | ||
|
|
44c61b8e7d | ||
|
|
8226f62ded | ||
|
|
d3b17f586d | ||
|
|
a556ba0959 | ||
|
|
ad40cd72ff | ||
|
|
9a22c3fce7 | ||
|
|
63e044ffdf | ||
|
|
2e794ee38f | ||
|
|
a1d4e062ed | ||
|
|
d2d2a28885 | ||
|
|
ead4242735 | ||
|
|
30a8c6b579 | ||
|
|
25df8f9c52 | ||
|
|
65d2389b2e | ||
|
|
7aa26580ba | ||
|
|
e4376bb9f2 | ||
|
|
0c08126752 | ||
|
|
ea64adc2f9 | ||
|
|
ad8ec68443 | ||
|
|
5e5fe2ccf3 | ||
|
|
2a34c8fa66 | ||
|
|
5e88e24693 | ||
|
|
988c5c6a25 | ||
|
|
d98c46a275 | ||
|
|
185b206627 | ||
|
|
cfb04f7d8a | ||
|
|
dba0c9f373 | ||
|
|
ee60652746 | ||
|
|
fbc79eae62 | ||
|
|
b356a634d1 | ||
|
|
b2ed5a01b3 | ||
|
|
839b172b92 | ||
|
|
745e120a0b | ||
|
|
a0ac603260 | ||
|
|
181ddce887 | ||
|
|
50043f889b | ||
|
|
49d1c5140e | ||
|
|
ab7a07a318 | ||
|
|
306e7abb47 | ||
|
|
cec4dfa6c3 | ||
|
|
21813a7b83 | ||
|
|
293573a0cd | ||
|
|
8695228537 | ||
|
|
24866a3e25 | ||
|
|
e871edc8f3 | ||
|
|
517f1992a1 | ||
|
|
e6adf3a522 | ||
|
|
32e9fd291d | ||
|
|
8229a97ffb | ||
|
|
6612a3a550 | ||
|
|
c44be53673 | ||
|
|
d100b0dc07 | ||
|
|
a0e9ac73c9 | ||
|
|
2e9ce962df | ||
|
|
93ad83d2ae | ||
|
|
72b1cc4d89 | ||
|
|
e70cca4736 | ||
|
|
d354c91d7c | ||
|
|
2d7b5e4aa2 | ||
|
|
b542a28673 | ||
|
|
ed52919f9e | ||
|
|
45a74a046c | ||
|
|
3192531d4c | ||
|
|
351bb760ae | ||
|
|
79a6baca6f | ||
|
|
f9645e8971 | ||
|
|
7611c83148 | ||
|
|
9881e6de3e | ||
|
|
53b4f0e0d5 | ||
|
|
9a645c24ca | ||
|
|
682d821b67 | ||
|
|
71afffaac1 | ||
|
|
a099876088 | ||
|
|
cf904a874e | ||
|
|
5a32a7ce18 | ||
|
|
6d6221636c | ||
|
|
8a4caaf6fb | ||
|
|
fa6d1879dd | ||
|
|
874b6c71a3 | ||
|
|
cd72ea524e | ||
|
|
56e8506cb9 | ||
|
|
c86be990d6 | ||
|
|
6b1f9d3243 | ||
|
|
117f1101e4 | ||
|
|
4284116280 | ||
|
|
d31b5ac99f | ||
|
|
b3f47bb2b6 | ||
|
|
64d8c7a657 | ||
|
|
4c3fcc3ea6 | ||
|
|
5ad47d3866 | ||
|
|
147160ed45 | ||
|
|
bfbb531863 | ||
|
|
48ba73e06d | ||
|
|
c922322ed3 | ||
|
|
53aaffd0f5 | ||
|
|
63a70f2ffa | ||
|
|
d8e9086bde | ||
|
|
af4470ead1 | ||
|
|
7cda81ec68 | ||
|
|
b1153f8d01 | ||
|
|
54e21bf249 | ||
|
|
eebf329983 | ||
|
|
7b1d6c3937 | ||
|
|
e6803e9a9b | ||
|
|
0b24011468 | ||
|
|
2699c995ee | ||
|
|
697f6ee2a9 | ||
|
|
35429f6a93 | ||
|
|
29eae4eeb6 | ||
|
|
8de67b6945 | ||
|
|
4f63284d41 | ||
|
|
0c806024fb | ||
|
|
9a08aa2ab5 | ||
|
|
02f218389b | ||
|
|
d3ec9f022c | ||
|
|
4cd54e5a9a | ||
|
|
6b4800d2d6 | ||
|
|
f60e4a1355 | ||
|
|
03897c5c9d | ||
|
|
ef90f1ff3f | ||
|
|
177a67f59b | ||
|
|
1e551581f8 | ||
|
|
62c2547557 | ||
|
|
2389ab30f8 | ||
|
|
fdffc27bb6 | ||
|
|
540d19c67c | ||
|
|
46eebdc7aa | ||
|
|
700c6ffc75 | ||
|
|
6b013c05cc | ||
|
|
f541bf186c | ||
|
|
9eb3075f65 | ||
|
|
e2b8dfe96a | ||
|
|
f883fde74a | ||
|
|
ae6f2624a0 | ||
|
|
ee2953a5e1 | ||
|
|
ec8ed65feb | ||
|
|
b70699ce1c | ||
|
|
5820f874fc | ||
|
|
44c0ecdbfa | ||
|
|
7be9db8b84 | ||
|
|
69d7684b0d | ||
|
|
a88582c610 | ||
|
|
3fd0c01c05 | ||
|
|
c16537aecf | ||
|
|
79f1eb6e5e | ||
|
|
a904e82d72 |
7
.eslintignore
Normal file
7
.eslintignore
Normal file
@@ -0,0 +1,7 @@
|
||||
node_modules
|
||||
dist
|
||||
bin
|
||||
docs
|
||||
libraries
|
||||
coverage
|
||||
play
|
||||
213
.eslintrc.js
Normal file
213
.eslintrc.js
Normal file
@@ -0,0 +1,213 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
commonjs: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
// plugins: ['prettier'], // to be activated
|
||||
extends: ['eslint:recommended', 'airbnb-base', 'plugin:jsonc/recommended-with-jsonc', 'prettier'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.json', '*.json5', '*.jsonc'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
},
|
||||
{
|
||||
files: ['package.json'],
|
||||
parser: 'jsonc-eslint-parser',
|
||||
rules: {
|
||||
'jsonc/sort-keys': [
|
||||
'off',
|
||||
{
|
||||
pathPattern: '^$',
|
||||
order: [
|
||||
'name',
|
||||
'version',
|
||||
'private',
|
||||
'packageManager',
|
||||
'description',
|
||||
'type',
|
||||
'keywords',
|
||||
'homepage',
|
||||
'bugs',
|
||||
'license',
|
||||
'author',
|
||||
'contributors',
|
||||
'funding',
|
||||
'files',
|
||||
'main',
|
||||
'module',
|
||||
'exports',
|
||||
'unpkg',
|
||||
'jsdelivr',
|
||||
'browser',
|
||||
'bin',
|
||||
'man',
|
||||
'directories',
|
||||
'repository',
|
||||
'publishConfig',
|
||||
'scripts',
|
||||
'peerDependencies',
|
||||
'peerDependenciesMeta',
|
||||
'optionalDependencies',
|
||||
'dependencies',
|
||||
'devDependencies',
|
||||
'engines',
|
||||
'config',
|
||||
'overrides',
|
||||
'pnpm',
|
||||
'husky',
|
||||
'lint-staged',
|
||||
'eslintConfig',
|
||||
],
|
||||
},
|
||||
{
|
||||
pathPattern: '^(?:dev|peer|optional|bundled)?[Dd]ependencies$',
|
||||
order: { type: 'asc' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
globals: {
|
||||
$: true,
|
||||
jQuery: true,
|
||||
glob: true,
|
||||
log: true,
|
||||
EditorWatchdog: true,
|
||||
baseApiUrl: true,
|
||||
// \src\share\canvas_share.js
|
||||
React: true,
|
||||
appState: true,
|
||||
ExcalidrawLib: true,
|
||||
elements: true,
|
||||
files: true,
|
||||
ReactDOM: true,
|
||||
// src\public\app\widgets\type_widgets\relation_map.js
|
||||
jsPlumb: true,
|
||||
panzoom: true,
|
||||
logError: true,
|
||||
// src\public\app\widgets\type_widgets\image.js
|
||||
WZoom: true,
|
||||
// \src\public\app\widgets\type_widgets\read_only_text.js
|
||||
renderMathInElement: true,
|
||||
// \src\public\app\widgets\type_widgets\editable_text.js
|
||||
BalloonEditor: true,
|
||||
CKEditorInspector: true,
|
||||
// \src\public\app\widgets\type_widgets\editable_code.js
|
||||
CodeMirror: true,
|
||||
// \src\public\app\services\resizer.js
|
||||
Split: true,
|
||||
// \src\public\app\services\note_content_renderer.js
|
||||
mermaid: true,
|
||||
// src\public\app\services\frontend_script_api.js
|
||||
dayjs: true,
|
||||
// \src\public\app\widgets\dialogs\markdown_import.js
|
||||
commonmark: true,
|
||||
// \src\public\app\widgets\note_map.js
|
||||
ForceGraph: true,
|
||||
// \src\public\app\setup.js
|
||||
ko: true,
|
||||
syncInProgress: true,
|
||||
// src\public\app\services\utils.js
|
||||
logInfo: true,
|
||||
__non_webpack_require__: true,
|
||||
//
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
},
|
||||
rules: {
|
||||
// eslint:recommended
|
||||
'no-unused-vars': 'off',
|
||||
'linebreak-style': 'off',
|
||||
'no-useless-escape': 'off',
|
||||
'no-empty': 'off',
|
||||
'no-constant-condition': 'off',
|
||||
'getter-return': 'off',
|
||||
'no-cond-assign': 'off',
|
||||
'no-async-promise-executor': 'off',
|
||||
'no-extra-semi': 'off',
|
||||
'no-inner-declarations': 'off',
|
||||
|
||||
// prettier
|
||||
'prettier/prettier': ['off', { endOfLine: 'auto' }],
|
||||
|
||||
// airbnb-base
|
||||
'no-console': 'off',
|
||||
'no-plusplus': 'off',
|
||||
'no-param-reassign': 'off',
|
||||
'global-require': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'no-await-in-loop': 'off',
|
||||
radix: 'off',
|
||||
'import/order': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'prefer-destructuring': 'off',
|
||||
'no-shadow': 'off',
|
||||
'no-new': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
strict: 'off',
|
||||
'class-methods-use-this': 'off',
|
||||
'no-else-return': 'off',
|
||||
'import/no-dynamic-require': 'off',
|
||||
'no-underscore-dangle': 'off',
|
||||
'prefer-template': 'off',
|
||||
'consistent-return': 'off',
|
||||
'no-continue': 'off',
|
||||
'object-shorthand': 'off',
|
||||
'one-var': 'off',
|
||||
'prefer-const': 'off',
|
||||
'spaced-comment': 'off',
|
||||
'no-loop-func': 'off',
|
||||
'arrow-body-style': 'off',
|
||||
|
||||
'guard-for-in': 'off',
|
||||
'no-return-assign': 'off',
|
||||
'dot-notation': 'off',
|
||||
|
||||
'func-names': 'off',
|
||||
'import/no-useless-path-segments': 'off',
|
||||
'default-param-last': 'off',
|
||||
'prefer-arrow-callback': 'off',
|
||||
'no-unneeded-ternary': 'off',
|
||||
'no-return-await': 'off',
|
||||
'import/extensions': 'off',
|
||||
|
||||
'no-var': 'off',
|
||||
'import/newline-after-import': 'off',
|
||||
'no-restricted-globals': 'off',
|
||||
'operator-assignment': 'off',
|
||||
'no-eval': 'off',
|
||||
'max-classes-per-file': 'off',
|
||||
'vars-on-top': 'off',
|
||||
'no-bitwise': 'off',
|
||||
'no-lonely-if': 'off',
|
||||
'no-multi-assign': 'off',
|
||||
'no-promise-executor-return': 'off',
|
||||
'no-empty-function': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
camelcase: 'off',
|
||||
eqeqeq: 'off',
|
||||
'lines-between-class-members': 'off',
|
||||
'import/no-cycle': 'off',
|
||||
'new-cap': 'off',
|
||||
'prefer-object-spread': 'off',
|
||||
'no-new-func': 'off',
|
||||
'no-unused-expressions': 'off',
|
||||
'lines-around-directive': 'off',
|
||||
'prefer-exponentiation-operator': 'off',
|
||||
'no-restricted-properties': 'off',
|
||||
'prefer-rest-params': 'off',
|
||||
'no-unreachable-loop': 'off',
|
||||
'no-alert': 'off',
|
||||
'no-useless-return': 'off',
|
||||
'no-nested-ternary': 'off',
|
||||
'prefer-regex-literals': 'off',
|
||||
'import/no-named-as-default-member': 'off',
|
||||
yoda: 'off',
|
||||
'no-script-url': 'off',
|
||||
'no-prototype-builtins':'off'
|
||||
},
|
||||
};
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ server-package.json
|
||||
.idea/httpRequests/
|
||||
data/
|
||||
tmp/
|
||||
.eslintcache
|
||||
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
_
|
||||
4
.husky/pre-commit
Normal file
4
.husky/pre-commit
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
#npx lint-staged
|
||||
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,7 +1,7 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
|
||||
6
.idea/jsLinters/eslint.xml
generated
Normal file
6
.idea/jsLinters/eslint.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EslintConfiguration">
|
||||
<option name="fix-on-save" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
11
.prettierrc.js
Normal file
11
.prettierrc.js
Normal file
@@ -0,0 +1,11 @@
|
||||
//https://prettier.io/docs/en/options.html
|
||||
module.exports = {
|
||||
semi: true,
|
||||
trailingComma: 'es5',
|
||||
singleQuote: true,
|
||||
printWidth: 120,
|
||||
tabWidth: 4,
|
||||
// useTabs: false,
|
||||
// bracketSpacing: true,
|
||||
// htmlWhitespaceSensitivity: 'ignore',
|
||||
};
|
||||
6
.vscode/extensions.json
vendored
Normal file
6
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
]
|
||||
}
|
||||
19
.vscode/launch.json
vendored
19
.vscode/launch.json
vendored
@@ -1,19 +1,24 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
// nodemon should be installed globally, use npm i -g nodemon
|
||||
{
|
||||
"type": "node",
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"name": "nodemon start-server",
|
||||
"program": "${workspaceFolder}/src/www",
|
||||
"request": "launch",
|
||||
"name": "start-server",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"restart": true,
|
||||
"runtimeExecutable": "nodemon",
|
||||
"env": {
|
||||
"TRILIUM_ENV": "dev",
|
||||
"TRILIUM_DATA_DIR": "./data"
|
||||
},
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"outputCapture": "std",
|
||||
"program": "${workspaceFolder}/src/www"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
33
.vscode/settings.json
vendored
Normal file
33
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"eslint.format.enable": true,
|
||||
"eslint.probe": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"html",
|
||||
"vue",
|
||||
"markdown",
|
||||
"json",
|
||||
"jsonc"
|
||||
],
|
||||
"eslint.validate": [
|
||||
"javascript",
|
||||
"javascriptreact",
|
||||
"typescript",
|
||||
"typescriptreact",
|
||||
"html",
|
||||
"vue",
|
||||
"markdown",
|
||||
"json",
|
||||
"jsonc"
|
||||
],
|
||||
"files.eol": "\n",
|
||||
}
|
||||
@@ -39,4 +39,4 @@ RUN adduser -s /bin/false node; exit 0
|
||||
EXPOSE 8080
|
||||
CMD [ "./start-docker.sh" ]
|
||||
|
||||
HEALTHCHECK --start-period=10s CMD node docker_healthcheck.js
|
||||
HEALTHCHECK --start-period=10s CMD exec su-exec node node docker_healthcheck.js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Trilium Notes
|
||||
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md) | [Japanese](https://github.com/zadam/trilium/blob/master/README.ja.md)
|
||||
|
||||
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
Trilium Notes 是一个层次化的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://github.com/zadam/trilium/wiki/Screenshot-tour)以快速了解:
|
||||
@@ -10,6 +10,7 @@ Trilium Notes 是一个层次化的笔记应用程序,专注于建立大型个
|
||||
Ukraine is currently suffering from Russian aggression, please consider donating to [one of these charities](https://old.reddit.com/r/ukraine/comments/s6g5un/want_to_support_ukraine_heres_a_list_of_charities/).
|
||||
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
|
||||
<img src="https://signmyrocket.com//uploads/2b2a523cd0c0e76cdbba95a89a9636b2_1676971281.jpg" alt="Trilium Notes supports Ukraine!" width="600"/>
|
||||
|
||||
## 特性
|
||||
|
||||
|
||||
83
README.ja.md
Normal file
83
README.ja.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# Trilium Notes
|
||||
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md) | [Japanese](https://github.com/zadam/trilium/blob/master/README.ja.md)
|
||||
|
||||
Trilium Notes は、大規模な個人知識ベースの構築に焦点を当てた、階層型ノートアプリケーションです。概要は[スクリーンショット](https://github.com/zadam/trilium/wiki/Screenshot-tour)をご覧ください:
|
||||
|
||||
<a href="https://github.com/zadam/trilium/wiki/Screenshot-tour"><img src="https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png" alt="Trilium Screenshot" width="1000"></a>
|
||||
|
||||
ウクライナは現在、ロシアの侵略から自国を守っています。[ウクライナ軍や人道的な慈善団体への寄付](https://standforukraine.com/)をご検討ください。
|
||||
|
||||
<p float="left">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="400"/>
|
||||
<img src="https://signmyrocket.com//uploads/2b2a523cd0c0e76cdbba95a89a9636b2_1676971281.jpg" alt="Trilium Notes supports Ukraine!" width="570"/>
|
||||
</p>
|
||||
|
||||
## 🎁 特徴
|
||||
|
||||
* ノートは、任意の深さのツリーに配置できます。単一のノートをツリー内の複数の場所に配置できます ([cloning](https://github.com/zadam/trilium/wiki/Cloning-notes) を参照)
|
||||
* マークダウン[オートフォーマット](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)による、表、画像、[数学](https://github.com/zadam/trilium/wiki/Text-notes#math-support)などの豊富な WYSIWYG ノート編集機能
|
||||
* シンタックスハイライトを含む[ソースコード付きノート](https://github.com/zadam/trilium/wiki/Code-notes)の編集をサポート
|
||||
* [ノート間のナビゲーション](https://github.com/zadam/trilium/wiki/Note-navigation)、全文検索、[ノートホイスト](https://github.com/zadam/trilium/wiki/Note-hoisting)が高速かつ簡単に行えます
|
||||
* シームレスな[ノートのバージョン管理](https://github.com/zadam/trilium/wiki/Note-revisions)
|
||||
* ノート[属性](https://github.com/zadam/trilium/wiki/Attributes)は、ノート整理、クエリ、高度な[スクリプト](https://github.com/zadam/trilium/wiki/Scripts)に使用できます
|
||||
* 自己ホスト型同期サーバーとの[同期](https://github.com/zadam/trilium/wiki/Synchronization)
|
||||
* [同期サーバーをホストするサードパーティ・サービス](https://trilium.cc/paid-hosting)があります
|
||||
* 公開インターネットへのノートの[共有](https://github.com/zadam/trilium/wiki/Sharing)(公開)
|
||||
* ノートごとの粒度を持つ強力な[ノート暗号化](https://github.com/zadam/trilium/wiki/Protected-notes)
|
||||
* 組み込みの Excalidraw を使用した図のスケッチ (ノート タイプ"キャンバス")
|
||||
* ノートとその関係を可視化するための[関係図](https://github.com/zadam/trilium/wiki/Relation-map)と[リンクマップ](https://github.com/zadam/trilium/wiki/Link-map)
|
||||
* [スクリプティング](https://github.com/zadam/trilium/wiki/Scripts) - [高度なショーケース](https://github.com/zadam/trilium/wiki/Advanced-showcases)を参照
|
||||
* 自動化のための [REST API](https://github.com/zadam/trilium/wiki/ETAPI)
|
||||
* ユーザビリティとパフォーマンスの両方で 100 000 ノート以上に拡張可能
|
||||
* スマートフォンとタブレット向けのタッチ最適化[モバイルフロントエンド](https://github.com/zadam/trilium/wiki/Mobile-frontend)
|
||||
* [ナイトテーマ](https://github.com/zadam/trilium/wiki/Themes)
|
||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) と [Markdown のインポートとエクスポート](https://github.com/zadam/trilium/wiki/Markdown)
|
||||
* Web コンテンツを簡単に保存するための [Web クリッパー](https://github.com/zadam/trilium/wiki/Web-clipper)
|
||||
|
||||
サードパーティのテーマ、スクリプト、プラグインなどは、 [awesome-trilium](https://github.com/Nriver/awesome-trilium) をチェックしてください。
|
||||
|
||||
## 🏗 ビルド
|
||||
|
||||
Trilium は、デスクトップアプリケーション(Linux、Windows)またはサーバー上でホストされるウェブアプリケーション(Linux)として提供されます。 Mac OS のデスクトップビルドも利用可能ですが、 [unsupported](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support) となっています。
|
||||
|
||||
* デスクトップで Trilium を使用したい場合は、 [latest release](https://github.com/zadam/trilium/releases/latest) からお使いのプラットフォームのバイナリリリースをダウンロードし、パッケージを解凍して ``trilium`` の実行ファイルを実行してください。
|
||||
* サーバーに Trilium をインストールする場合は、[このページ](https://github.com/zadam/trilium/wiki/Server-installation)に従ってください。
|
||||
* 現在、対応(動作確認)しているブラウザは、最近の Chrome と Firefox のみです。
|
||||
|
||||
Trilium は Flatpak としても提供されます:
|
||||
|
||||
[<img width="240" src="https://flathub.org/assets/badges/flathub-badge-en.png">](https://flathub.org/apps/details/com.github.zadam.trilium)
|
||||
|
||||
## 📝 ドキュメント
|
||||
|
||||
[ドキュメントページの全リストはwikiをご覧ください。](https://github.com/zadam/trilium/wiki/)
|
||||
|
||||
また、[個人的な知識基盤のパターン](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base)を読むと、 Trilium の使い方のヒントを得ることができます。
|
||||
|
||||
## 💻 コントリビュート
|
||||
|
||||
ブラウザベースの開発環境を使用
|
||||
|
||||
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||
|
||||
または、ローカルにクローンして実行
|
||||
```
|
||||
npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
## 📢 シャウトアウト
|
||||
|
||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - 市場で最高の WYSIWYG エディター、非常にインタラクティブで聞き上手なチーム
|
||||
* [FancyTree](https://github.com/mar10/fancytree) - 真の競争相手がいない、非常に機能豊富なツリーライブラリです。 Trilium Notes は、これなしでは成り立たないでしょう。
|
||||
* [CodeMirror](https://github.com/codemirror/CodeMirror) - 膨大な数の言語をサポートするコードエディタ
|
||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - 競合のないビジュアルコネクティビティライブラリです。[関係図](https://github.com/zadam/trilium/wiki/Relation-map)、[リンク図](https://github.com/zadam/trilium/wiki/Link-map)で使用。
|
||||
|
||||
## 🤝 サポート
|
||||
|
||||
GitHub スポンサー、[PayPal](https://paypal.me/za4am)もしくは Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2) にて Trilium をサポートすることができます。
|
||||
|
||||
## 🔑 ライセンス
|
||||
|
||||
このプログラムはフリーソフトウェアです:フリーソフトウェア財団が発行した GNU Affero General Public License のバージョン3、またはそれ以降のバージョンのいずれかに従って、再配布および/または改変することができます。
|
||||
28
README.md
28
README.md
@@ -1,17 +1,19 @@
|
||||
# Trilium Notes
|
||||
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md) | [Japanese](https://github.com/zadam/trilium/blob/master/README.ja.md)
|
||||
|
||||
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases. See [screenshots](https://github.com/zadam/trilium/wiki/Screenshot-tour) for quick overview:
|
||||
|
||||

|
||||
<a href="https://github.com/zadam/trilium/wiki/Screenshot-tour"><img src="https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png" alt="Trilium Screenshot" width="1000"></a>
|
||||
|
||||
Ukraine is currently defending itself from Russian aggression, please consider [donating to Ukrainian Army or humanitarian charities](https://standforukraine.com/).
|
||||
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
|
||||
<p float="left">
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="400"/>
|
||||
<img src="https://signmyrocket.com//uploads/2b2a523cd0c0e76cdbba95a89a9636b2_1676971281.jpg" alt="Trilium Notes supports Ukraine!" width="570"/>
|
||||
</p>
|
||||
|
||||
## Features
|
||||
## 🎁 Features
|
||||
|
||||
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes))
|
||||
* Rich WYSIWYG note editing including e.g. tables, images and [math](https://github.com/zadam/trilium/wiki/Text-notes#math-support) with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)
|
||||
@@ -33,7 +35,9 @@ Ukraine is currently defending itself from Russian aggression, please consider [
|
||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
|
||||
* [Web Clipper](https://github.com/zadam/trilium/wiki/Web-clipper) for easy saving of web content
|
||||
|
||||
## Builds
|
||||
Check out [awesome-trilium](https://github.com/Nriver/awesome-trilium) for 3rd party themes, scripts, plugins and more.
|
||||
|
||||
## 🏗 Builds
|
||||
|
||||
Trilium is provided as either desktop application (Linux and Windows) or web application hosted on your server (Linux). Mac OS desktop build is available, but it is [unsupported](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support).
|
||||
|
||||
@@ -45,13 +49,13 @@ Trilium is also provided as a Flatpak:
|
||||
|
||||
[<img width="240" src="https://flathub.org/assets/badges/flathub-badge-en.png">](https://flathub.org/apps/details/com.github.zadam.trilium)
|
||||
|
||||
## Documentation
|
||||
## 📝 Documentation
|
||||
|
||||
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
|
||||
|
||||
You can also read [Patterns of personal knowledge base](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base) to get some inspiration on how you might use Trilium.
|
||||
|
||||
## Contribute
|
||||
## 💻 Contribute
|
||||
|
||||
Use a browser based dev environment
|
||||
|
||||
@@ -63,17 +67,17 @@ npm install
|
||||
npm run start-server
|
||||
```
|
||||
|
||||
## Shoutouts
|
||||
## 📢 Shoutouts
|
||||
|
||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - best WYSIWYG editor on the market, very interactive and listening team
|
||||
* [FancyTree](https://github.com/mar10/fancytree) - very feature rich tree library without real competition. Trilium Notes would not be the same without it.
|
||||
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
|
||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map)
|
||||
|
||||
## Donating
|
||||
## 🤝 Support
|
||||
|
||||
You can donate using GitHub Sponsors, [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
|
||||
You can support Trilium using GitHub Sponsors, [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
|
||||
|
||||
## License
|
||||
## 🔑 License
|
||||
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Trilium Notes
|
||||
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md)
|
||||
[English](https://github.com/zadam/trilium/blob/master/README.md) | [Chinese](https://github.com/zadam/trilium/blob/master/README-ZH_CN.md) | [Russian](https://github.com/zadam/trilium/blob/master/README.ru.md) | [Japanese](https://github.com/zadam/trilium/blob/master/README.ja.md)
|
||||
|
||||
[](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
Trilium Notes – это приложение для заметок с иерархической структурой, ориентированное на создание больших персональных баз знаний. Для быстрого ознакомления посмотрите [скриншот-тур](https://github.com/zadam/trilium/wiki/Screenshot-tour):
|
||||
@@ -10,6 +10,7 @@ Trilium Notes – это приложение для заметок с иера
|
||||
Ukraine is currently suffering from Russian aggression, please consider donating to [one of these charities](https://old.reddit.com/r/ukraine/comments/s6g5un/want_to_support_ukraine_heres_a_list_of_charities/).
|
||||
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
|
||||
<img src="https://signmyrocket.com//uploads/2b2a523cd0c0e76cdbba95a89a9636b2_1676971281.jpg" alt="Trilium Notes supports Ukraine!" width="600"/>
|
||||
|
||||
## Возможности
|
||||
|
||||
|
||||
@@ -1,12 +1,161 @@
|
||||
|
||||
UPDATE etapi_tokens SET tokenHash = 'API token hash value';
|
||||
UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share');
|
||||
UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\';
|
||||
UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL;
|
||||
UPDATE note_revisions SET title = 'title';
|
||||
UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL;
|
||||
|
||||
UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
|
||||
UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'inherit', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
|
||||
UPDATE attributes SET name = 'name', value = 'value'
|
||||
WHERE type = 'label'
|
||||
AND name NOT IN ('inbox',
|
||||
'disableVersioning',
|
||||
'calendarRoot',
|
||||
'archived',
|
||||
'excludeFromExport',
|
||||
'disableInclusion',
|
||||
'appCss',
|
||||
'appTheme',
|
||||
'hidePromotedAttributes',
|
||||
'readOnly',
|
||||
'autoReadOnlyDisabled',
|
||||
'cssClass',
|
||||
'iconClass',
|
||||
'keyboardShortcut',
|
||||
'run',
|
||||
'runOnInstance',
|
||||
'runAtHour',
|
||||
'customRequestHandler',
|
||||
'customResourceProvider',
|
||||
'widget',
|
||||
'noteInfoWidgetDisabled',
|
||||
'linkMapWidgetDisabled',
|
||||
'noteRevisionsWidgetDisabled',
|
||||
'whatLinksHereWidgetDisabled',
|
||||
'similarNotesWidgetDisabled',
|
||||
'workspace',
|
||||
'workspaceIconClass',
|
||||
'workspaceTabBackgroundColor',
|
||||
'searchHome',
|
||||
'workspaceInbox',
|
||||
'workspaceSearchHome',
|
||||
'sqlConsoleHome',
|
||||
'datePattern',
|
||||
'pageSize',
|
||||
'viewType',
|
||||
'mapRootNoteId',
|
||||
'bookmarkFolder',
|
||||
'sorted',
|
||||
'top',
|
||||
'fullContentWidth',
|
||||
'shareHiddenFromTree',
|
||||
'shareAlias',
|
||||
'shareOmitDefaultCss',
|
||||
'shareRoot',
|
||||
'internalLink',
|
||||
'imageLink',
|
||||
'relationMapLink',
|
||||
'includeMapLink',
|
||||
'runOnNoteCreation',
|
||||
'runOnNoteTitleChange',
|
||||
'runOnNoteContentChange',
|
||||
'runOnNoteChange',
|
||||
'runOnChildNoteCreation',
|
||||
'runOnAttributeCreation',
|
||||
'runOnAttributeChange',
|
||||
'template',
|
||||
'inherit',
|
||||
'widget',
|
||||
'renderNote',
|
||||
'shareCss',
|
||||
'shareJs',
|
||||
'shareFavicon',
|
||||
'executeButton',
|
||||
'keepCurrentHoisting',
|
||||
'color',
|
||||
'toc',
|
||||
'excludeFromNoteMap',
|
||||
'docName',
|
||||
'launcherType',
|
||||
'builtinWidget',
|
||||
'baseSize',
|
||||
'growthFactor'
|
||||
);
|
||||
|
||||
UPDATE attributes SET name = 'name'
|
||||
AND name NOT IN ('inbox',
|
||||
'disableVersioning',
|
||||
'calendarRoot',
|
||||
'archived',
|
||||
'excludeFromExport',
|
||||
'disableInclusion',
|
||||
'appCss',
|
||||
'appTheme',
|
||||
'hidePromotedAttributes',
|
||||
'readOnly',
|
||||
'autoReadOnlyDisabled',
|
||||
'cssClass',
|
||||
'iconClass',
|
||||
'keyboardShortcut',
|
||||
'run',
|
||||
'runOnInstance',
|
||||
'runAtHour',
|
||||
'customRequestHandler',
|
||||
'customResourceProvider',
|
||||
'widget',
|
||||
'noteInfoWidgetDisabled',
|
||||
'linkMapWidgetDisabled',
|
||||
'noteRevisionsWidgetDisabled',
|
||||
'whatLinksHereWidgetDisabled',
|
||||
'similarNotesWidgetDisabled',
|
||||
'workspace',
|
||||
'workspaceIconClass',
|
||||
'workspaceTabBackgroundColor',
|
||||
'searchHome',
|
||||
'workspaceInbox',
|
||||
'workspaceSearchHome',
|
||||
'sqlConsoleHome',
|
||||
'datePattern',
|
||||
'pageSize',
|
||||
'viewType',
|
||||
'mapRootNoteId',
|
||||
'bookmarkFolder',
|
||||
'sorted',
|
||||
'top',
|
||||
'fullContentWidth',
|
||||
'shareHiddenFromTree',
|
||||
'shareAlias',
|
||||
'shareOmitDefaultCss',
|
||||
'shareRoot',
|
||||
'internalLink',
|
||||
'imageLink',
|
||||
'relationMapLink',
|
||||
'includeMapLink',
|
||||
'runOnNoteCreation',
|
||||
'runOnNoteTitleChange',
|
||||
'runOnNoteContentChange',
|
||||
'runOnNoteChange',
|
||||
'runOnChildNoteCreation',
|
||||
'runOnAttributeCreation',
|
||||
'runOnAttributeChange',
|
||||
'template',
|
||||
'inherit',
|
||||
'widget',
|
||||
'renderNote',
|
||||
'shareCss',
|
||||
'shareJs',
|
||||
'shareFavicon',
|
||||
'executeButton',
|
||||
'keepCurrentHoisting',
|
||||
'color',
|
||||
'toc',
|
||||
'excludeFromNoteMap',
|
||||
'docName',
|
||||
'launcherType',
|
||||
'builtinWidget',
|
||||
'baseSize',
|
||||
'growthFactor'
|
||||
);
|
||||
|
||||
UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered';
|
||||
UPDATE options SET value = 'anonymized' WHERE name IN
|
||||
('documentId', 'documentSecret', 'encryptedDataKey',
|
||||
|
||||
@@ -2,12 +2,18 @@ module.exports = () => {
|
||||
const cls = require("../../src/services/cls");
|
||||
const beccaLoader = require("../../src/becca/becca_loader");
|
||||
const becca = require("../../src/becca/becca");
|
||||
const log = require("../../src/services/log");
|
||||
|
||||
cls.init(() => {
|
||||
beccaLoader.load();
|
||||
|
||||
const hidden = becca.getNote("_hidden");
|
||||
|
||||
if (!hidden) {
|
||||
log.info("MIGRATION 212: no _hidden note, skipping.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const noteId of hidden.getSubtreeNoteIds({includeHidden: true})) {
|
||||
if (noteId.startsWith("_")) { // is "named" note
|
||||
const note = becca.getNote(noteId);
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
const http = require("http");
|
||||
const config = require("./src/services/config");
|
||||
const ini = require("ini");
|
||||
const fs = require("fs");
|
||||
const dataDir = require("./src/services/data_dir");
|
||||
const config = ini.parse(fs.readFileSync(dataDir.CONFIG_INI_PATH, 'utf-8'));
|
||||
|
||||
if (config.https) {
|
||||
// built-in TLS (terminated by trilium) is not supported yet, PRs are welcome
|
||||
// for reverse proxy terminated TLS this will works since config.https will be false
|
||||
process.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const port = require('./src/services/port');
|
||||
const host = require('./src/services/host');
|
||||
const url = `http://${host}:${port}/api/health-check`;
|
||||
|
||||
const options = { timeout: 2000 };
|
||||
const request = http.request(url, options, res => {
|
||||
|
||||
const callback = res => {
|
||||
console.log(`STATUS: ${res.statusCode}`);
|
||||
if (res.statusCode === 200) {
|
||||
process.exit(0);
|
||||
} else {
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let request;
|
||||
|
||||
if (port !== 0) { // TCP socket.
|
||||
const url = `http://${host}:${port}/api/health-check`;
|
||||
request = http.request(url, options, callback);
|
||||
} else { // Unix socket.
|
||||
options.socketPath = host;
|
||||
options.path = '/api/health-check';
|
||||
request = http.request(options, callback);
|
||||
}
|
||||
|
||||
request.on("error", err => {
|
||||
console.log("ERROR");
|
||||
process.exit(1);
|
||||
});
|
||||
request.end();
|
||||
request.end();
|
||||
|
||||
@@ -991,7 +991,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1904,7 +1904,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1916,7 +1916,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1461,7 +1461,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2174,7 +2174,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -267,7 +267,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line24">line 24</a>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line29">line 29</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line20">line 20</a>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line25">line 25</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line26">line 26</a>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line31">line 31</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -471,7 +471,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line22">line 22</a>
|
||||
<a href="becca_entities_boption.js.html">becca/entities/boption.js</a>, <a href="becca_entities_boption.js.html#line27">line 27</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1251,7 +1251,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -3254,7 +3254,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="ensureNoteIsPresentInParent"><span class="type-signature"></span>ensureNoteIsPresentInParent<span class="signature">(noteId, parentNoteId, prefix)</span><span class="type-signature"> → {void}</span></h4>
|
||||
<h4 class="name" id="ensureNoteIsPresentInParent"><span class="type-signature"></span>ensureNoteIsPresentInParent<span class="signature">(noteId, parentNoteId, prefix)</span><span class="type-signature"> → {Object}</span></h4>
|
||||
|
||||
|
||||
|
||||
@@ -3262,7 +3262,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
|
||||
|
||||
<div class="description">
|
||||
If there's no branch between note and parent note, create one. Otherwise, do nothing.
|
||||
If there's no branch between note and parent note, create one. Otherwise, do nothing. Returns the new or existing branch.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3437,7 +3437,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">void</span>
|
||||
<span class="param-type">Object</span>
|
||||
|
||||
|
||||
</dd>
|
||||
@@ -7889,7 +7889,7 @@ exists, then we'll use that transaction.
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -212,7 +212,7 @@ module.exports = AbstractBeccaEntity;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -124,7 +124,7 @@ class BAttribute extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
if (this.type === 'relation' && !(this.value in this.becca.notes)) {
|
||||
throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it target not existing note '${this.value}'.`);
|
||||
throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it targets not existing note '${this.value}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ module.exports = BAttribute;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -319,7 +319,7 @@ module.exports = BBranch;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -120,7 +120,7 @@ module.exports = BEtapiToken;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -125,7 +125,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
* @private */
|
||||
this.parents = [];
|
||||
/** @type {BNote[]}
|
||||
* @private*/
|
||||
* @private */
|
||||
this.children = [];
|
||||
/** @type {BAttribute[]}
|
||||
* @private */
|
||||
@@ -135,11 +135,11 @@ class BNote extends AbstractBeccaEntity {
|
||||
* @private */
|
||||
this.__attributeCache = null;
|
||||
/** @type {BAttribute[]|null}
|
||||
* @private*/
|
||||
* @private */
|
||||
this.inheritableAttributeCache = null;
|
||||
|
||||
/** @type {BAttribute[]}
|
||||
* @private*/
|
||||
* @private */
|
||||
this.targetRelations = [];
|
||||
|
||||
this.becca.addNote(this.noteId, this);
|
||||
@@ -560,6 +560,20 @@ class BNote extends AbstractBeccaEntity {
|
||||
*/
|
||||
hasLabel(name, value) { return this.hasAttribute(LABEL, name, value); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {boolean} true if label exists (including inherited) and does not have "false" value.
|
||||
*/
|
||||
isLabelTruthy(name) {
|
||||
const label = this.getLabel(name);
|
||||
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return label && label.value !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @param {string} [value] - label value
|
||||
@@ -761,6 +775,21 @@ class BNote extends AbstractBeccaEntity {
|
||||
return this.hasAttribute('label', 'archived');
|
||||
}
|
||||
|
||||
areAllNotePathsArchived() {
|
||||
// there's a slight difference between note being itself archived and all its note paths being archived
|
||||
// - note is archived when it itself has an archived label or inherits it
|
||||
// - note does not have or inherit archived label, but each note paths contains a note with (non-inheritable)
|
||||
// archived label
|
||||
|
||||
const bestNotePathRecord = this.getSortedNotePathRecords()[0];
|
||||
|
||||
if (!bestNotePathRecord) {
|
||||
throw new Error(`No note path available for note '${this.noteId}'`);
|
||||
}
|
||||
|
||||
return bestNotePathRecord.isArchived;
|
||||
}
|
||||
|
||||
hasInheritableArchivedLabel() {
|
||||
for (const attr of this.getAttributes()) {
|
||||
if (attr.name === 'archived' && attr.type === LABEL && attr.isInheritable) {
|
||||
@@ -1164,6 +1193,8 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives all possible note paths leading to this note. Paths containing search note are ignored (could form cycles)
|
||||
*
|
||||
* @returns {string[][]} - array of notePaths (each represented by array of noteIds constituting the particular note path)
|
||||
*/
|
||||
getAllNotePaths() {
|
||||
@@ -1171,18 +1202,73 @@ class BNote extends AbstractBeccaEntity {
|
||||
return [['root']];
|
||||
}
|
||||
|
||||
const notePaths = [];
|
||||
const parentNotes = this.getParentNotes();
|
||||
let notePaths = [];
|
||||
|
||||
for (const parentNote of this.getParentNotes()) {
|
||||
for (const parentPath of parentNote.getAllNotePaths()) {
|
||||
parentPath.push(this.noteId);
|
||||
notePaths.push(parentPath);
|
||||
}
|
||||
if (parentNotes.length === 1) { // optimization for most common case
|
||||
notePaths = parentNotes[0].getAllNotePaths();
|
||||
} else {
|
||||
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
|
||||
}
|
||||
|
||||
for (const notePath of notePaths) {
|
||||
notePath.push(this.noteId);
|
||||
}
|
||||
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, notePath: Array<string>, isHidden: boolean}>}
|
||||
*/
|
||||
getSortedNotePathRecords(hoistedNoteId = 'root') {
|
||||
const isHoistedRoot = hoistedNoteId === 'root';
|
||||
|
||||
const notePaths = this.getAllNotePaths().map(path => ({
|
||||
notePath: path,
|
||||
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
||||
isArchived: path.some(noteId => this.becca.notes[noteId].isArchived),
|
||||
isHidden: path.includes('_hidden')
|
||||
}));
|
||||
|
||||
notePaths.sort((a, b) => {
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
return a.isArchived ? 1 : -1;
|
||||
} else if (a.isHidden !== b.isHidden) {
|
||||
return a.isHidden ? 1 : -1;
|
||||
} else {
|
||||
return a.notePath.length - b.notePath.length;
|
||||
}
|
||||
});
|
||||
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string[]} array of noteIds constituting the particular note path
|
||||
*/
|
||||
getBestNotePath(hoistedNoteId = 'root') {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId)[0]?.notePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string} serialized note path (e.g. 'root/a1h315/js725h')
|
||||
*/
|
||||
getBestNotePathString(hoistedNoteId = 'root') {
|
||||
const notePath = this.getBestNotePath(hoistedNoteId);
|
||||
|
||||
return notePath?.join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean - true if there's no non-hidden path, note is not cloned to the visible tree
|
||||
*/
|
||||
@@ -1196,9 +1282,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
return false;
|
||||
} else if (parentNote.noteId === '_hidden') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parentNote.isHiddenCompletely()) {
|
||||
} else if (!parentNote.isHiddenCompletely()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1392,7 +1476,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
|
||||
/**
|
||||
* @param parentNoteId
|
||||
* @returns {{success: boolean, message: string}}
|
||||
* @returns {{success: boolean, message: string, branchId: string, notePath: string}}
|
||||
*/
|
||||
cloneTo(parentNoteId) {
|
||||
const cloningService = require("../../services/cloning");
|
||||
@@ -1550,7 +1634,7 @@ module.exports = BNote;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -194,12 +194,14 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
utcDateLastEdited: this.utcDateLastEdited,
|
||||
utcDateCreated: this.utcDateCreated,
|
||||
utcDateModified: this.utcDateModified,
|
||||
content: this.content, // used when retrieving full note revision to frontend
|
||||
contentLength: this.contentLength
|
||||
};
|
||||
}
|
||||
|
||||
getPojoToSave() {
|
||||
const pojo = this.getPojo();
|
||||
delete pojo.content; // not getting persisted
|
||||
delete pojo.contentLength; // not getting persisted
|
||||
|
||||
if (pojo.isProtected) {
|
||||
@@ -233,7 +235,7 @@ module.exports = BNoteRevision;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -44,6 +44,11 @@ class BOption extends AbstractBeccaEntity {
|
||||
constructor(row) {
|
||||
super();
|
||||
|
||||
this.updateFromRow(row);
|
||||
this.becca.options[this.name] = this;
|
||||
}
|
||||
|
||||
updateFromRow(row) {
|
||||
/** @type {string} */
|
||||
this.name = row.name;
|
||||
/** @type {string} */
|
||||
@@ -52,8 +57,6 @@ class BOption extends AbstractBeccaEntity {
|
||||
this.isSynced = !!row.isSynced;
|
||||
/** @type {string} */
|
||||
this.utcDateModified = row.utcDateModified;
|
||||
|
||||
this.becca.options[this.name] = this;
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
@@ -89,7 +92,7 @@ module.exports = BOption;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -77,7 +77,7 @@ module.exports = BRecentNote;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1300,7 +1300,7 @@
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -165,13 +165,13 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
this.getNoteWithLabel = attributeService.getNoteWithLabel;
|
||||
|
||||
/**
|
||||
* If there's no branch between note and parent note, create one. Otherwise, do nothing.
|
||||
* If there's no branch between note and parent note, create one. Otherwise, do nothing. Returns the new or existing branch.
|
||||
*
|
||||
* @method
|
||||
* @param {string} noteId
|
||||
* @param {string} parentNoteId
|
||||
* @param {string} prefix - if branch will be created between note and parent note, set this prefix
|
||||
* @returns {void}
|
||||
* @returns {{branch: BBranch|null}}
|
||||
*/
|
||||
this.ensureNoteIsPresentInParent = cloningService.ensureNoteIsPresentInParent;
|
||||
|
||||
@@ -499,11 +499,11 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
if (opts.type === 'script' && !opts.scriptNoteId) { throw new Error("scriptNoteId is mandatory for launchers of type 'script'"); }
|
||||
if (opts.type === 'customWidget' && !opts.widgetNoteId) { throw new Error("widgetNoteId is mandatory for launchers of type 'customWidget'"); }
|
||||
|
||||
const parentNoteId = !!opts.isVisible ? '_lbVisibleLaunchers' : '_lbAvailableLaunchers';
|
||||
const parentNoteId = opts.isVisible ? '_lbVisibleLaunchers' : '_lbAvailableLaunchers';
|
||||
const noteId = 'al_' + opts.id;
|
||||
|
||||
const launcherNote =
|
||||
becca.getNote(opts.id) ||
|
||||
becca.getNote(noteId) ||
|
||||
specialNotesService.createLauncher({
|
||||
noteId: noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
@@ -542,7 +542,7 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
if (opts.icon) {
|
||||
launcherNote.setLabel('iconClass', `bx ${opts.icon}`);
|
||||
} else {
|
||||
launcherNote.removeLabel('keyboardShortcut');
|
||||
launcherNote.removeLabel('iconClass');
|
||||
}
|
||||
|
||||
return {note: launcherNote};
|
||||
@@ -584,7 +584,7 @@ module.exports = BackendScriptApi;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -245,7 +245,7 @@ function wrap(query, func) {
|
||||
// in these cases error should be simply ignored.
|
||||
console.log(e.message);
|
||||
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
throw e;
|
||||
@@ -309,7 +309,7 @@ function fillParamList(paramIds, truncate = true) {
|
||||
}
|
||||
|
||||
// doing it manually to avoid this showing up on the sloq query list
|
||||
const s = stmt(`INSERT INTO param_list VALUES ${paramIds.map(paramId => `(?)`).join(',')}`, paramIds);
|
||||
const s = stmt(`INSERT INTO param_list VALUES ${paramIds.map(paramId => `(?)`).join(',')}`);
|
||||
|
||||
s.run(paramIds);
|
||||
}
|
||||
@@ -413,7 +413,7 @@ module.exports = {
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -850,7 +850,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -1062,7 +1062,7 @@ parents.</div>
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -781,7 +781,7 @@
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -342,115 +342,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line69">line 69</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="CollapsibleWidget"><span class="type-signature"></span>CollapsibleWidget<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">RightPanelWidget</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use api.RightPanelWidget instead</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line42">line 42</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line45">line 45</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -556,115 +448,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line48">line 48</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="NoteContextCachingWidget"><span class="type-signature"></span>NoteContextCachingWidget<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">NoteContextAwareWidget</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use NoteContextAwareWidget instead</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line66">line 66</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line42">line 42</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -770,223 +554,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line45">line 45</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="TabAwareWidget"><span class="type-signature"></span>TabAwareWidget<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">NoteContextAwareWidget</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use NoteContextAwareWidget instead</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line54">line 54</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="TabCachingWidget"><span class="type-signature"></span>TabCachingWidget<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">NoteContextAwareWidget</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>use NoteContextAwareWidget instead</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line60">line 60</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line39">line 39</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1558,7 +1126,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line88">line 88</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line64">line 64</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1713,7 +1281,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line78">line 78</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line54">line 54</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2054,7 +1622,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line148">line 148</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line124">line 124</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2191,7 +1759,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line337">line 337</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line313">line 313</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2399,7 +1967,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line479">line 479</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line455">line 455</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2781,7 +2349,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line329">line 329</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line305">line 305</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2914,7 +2482,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line275">line 275</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line251">line 251</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3024,7 +2592,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line359">line 359</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line335">line 335</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3130,7 +2698,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line343">line 343</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line319">line 319</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3236,7 +2804,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line374">line 374</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line350">line 350</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3346,7 +2914,7 @@ available in the JS frontend notes. You can use e.g. <code>api.showMessage(api.s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line351">line 351</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line327">line 327</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3457,7 +3025,7 @@ implementation of actual widget type.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line368">line 368</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line344">line 344</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3612,7 +3180,7 @@ implementation of actual widget type.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line383">line 383</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line359">line 359</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3767,7 +3335,7 @@ implementation of actual widget type.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line427">line 427</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line403">line 403</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3874,7 +3442,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line268">line 268</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line244">line 244</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4029,7 +3597,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line445">line 445</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line421">line 421</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4185,7 +3753,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line238">line 238</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line214">line 214</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4386,7 +3954,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line251">line 251</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line227">line 227</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4492,7 +4060,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line418">line 418</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line394">line 394</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4647,7 +4215,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line436">line 436</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line412">line 412</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4802,7 +4370,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line454">line 454</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line430">line 430</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4952,7 +4520,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line519">line 519</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line495">line 495</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5130,7 +4698,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line121">line 121</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line97">line 97</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5308,7 +4876,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line103">line 103</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line79">line 79</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5459,7 +5027,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line282">line 282</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line258">line 258</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5637,7 +5205,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line398">line 398</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line374">line 374</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5811,7 +5379,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line408">line 408</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line384">line 384</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5966,7 +5534,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line508">line 508</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line484">line 484</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6120,7 +5688,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line499">line 499</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line475">line 475</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6275,7 +5843,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line259">line 259</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line235">line 235</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6436,7 +6004,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line181">line 181</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line157">line 157</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6596,7 +6164,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line225">line 225</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line201">line 201</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6752,7 +6320,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line213">line 213</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line189">line 189</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6907,7 +6475,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line463">line 463</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line439">line 439</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7058,7 +6626,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line390">line 390</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line366">line 366</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7213,7 +6781,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line298">line 298</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line274">line 274</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7350,7 +6918,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line290">line 290</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line266">line 266</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7510,7 +7078,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line307">line 307</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line283">line 283</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7670,7 +7238,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line316">line 316</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line292">line 292</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7762,7 +7330,7 @@ Typical use case is when new note has been created, we should wait until it is s
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line491">line 491</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line467">line 467</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7832,7 +7400,7 @@ Typical use case is when new note has been created, we should wait until it is s
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -121,7 +121,7 @@ export default FAttribute;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -105,7 +105,7 @@ export default FBranch;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -101,7 +101,7 @@ class FNote {
|
||||
this.mime = row.mime;
|
||||
}
|
||||
|
||||
addParent(parentNoteId, branchId) {
|
||||
addParent(parentNoteId, branchId, sort = true) {
|
||||
if (parentNoteId === 'none') {
|
||||
return;
|
||||
}
|
||||
@@ -111,6 +111,10 @@ class FNote {
|
||||
}
|
||||
|
||||
this.parentToBranch[parentNoteId] = branchId;
|
||||
|
||||
if (sort) {
|
||||
this.sortParents();
|
||||
}
|
||||
}
|
||||
|
||||
addChild(childNoteId, branchId, sort = true) {
|
||||
@@ -217,7 +221,7 @@ class FNote {
|
||||
|
||||
// will sort the parents so that non-search & non-archived are first and archived at the end
|
||||
// this is done so that non-search & non-archived paths are always explored as first when looking for note path
|
||||
resortParents() {
|
||||
sortParents() {
|
||||
this.parents.sort((aNoteId, bNoteId) => {
|
||||
const aBranchId = this.parentToBranch[aNoteId];
|
||||
|
||||
@@ -225,7 +229,7 @@ class FNote {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const aNote = this.froca.getNoteFromCache([aNoteId]);
|
||||
const aNote = this.froca.getNoteFromCache(aNoteId);
|
||||
|
||||
if (aNote.isArchived || aNote.isHiddenCompletely()) {
|
||||
return 1;
|
||||
@@ -271,6 +275,11 @@ class FNote {
|
||||
return this.__filterAttrs(this.__getCachedAttributes([]), type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} path
|
||||
* @return {FAttribute[]}
|
||||
* @private
|
||||
*/
|
||||
__getCachedAttributes(path) {
|
||||
// notes/clones cannot form tree cycles, it is possible to create attribute inheritance cycle via templates
|
||||
// when template instance is a parent of template itself
|
||||
@@ -323,63 +332,49 @@ class FNote {
|
||||
return this.noteId === 'root';
|
||||
}
|
||||
|
||||
getAllNotePaths(encounteredNoteIds = null) {
|
||||
/**
|
||||
* Gives all possible note paths leading to this note. Paths containing search note are ignored (could form cycles)
|
||||
*
|
||||
* @returns {string[][]} - array of notePaths (each represented by array of noteIds constituting the particular note path)
|
||||
*/
|
||||
getAllNotePaths() {
|
||||
if (this.noteId === 'root') {
|
||||
return [['root']];
|
||||
}
|
||||
|
||||
if (!encounteredNoteIds) {
|
||||
encounteredNoteIds = new Set();
|
||||
const parentNotes = this.getParentNotes().filter(note => note.type !== 'search');
|
||||
let notePaths = [];
|
||||
|
||||
if (parentNotes.length === 1) { // optimization for most common case
|
||||
notePaths = parentNotes[0].getAllNotePaths();
|
||||
} else {
|
||||
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
|
||||
}
|
||||
|
||||
encounteredNoteIds.add(this.noteId);
|
||||
|
||||
const parentNotes = this.getParentNotes();
|
||||
let paths;
|
||||
|
||||
if (parentNotes.length === 1) { // optimization for the most common case
|
||||
if (encounteredNoteIds.has(parentNotes[0].noteId)) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
paths = parentNotes[0].getAllNotePaths(encounteredNoteIds);
|
||||
}
|
||||
}
|
||||
else {
|
||||
paths = [];
|
||||
|
||||
for (const parentNote of parentNotes) {
|
||||
if (encounteredNoteIds.has(parentNote.noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newSet = new Set(encounteredNoteIds);
|
||||
|
||||
paths.push(...parentNote.getAllNotePaths(newSet));
|
||||
}
|
||||
for (const notePath of notePaths) {
|
||||
notePath.push(this.noteId);
|
||||
}
|
||||
|
||||
for (const path of paths) {
|
||||
path.push(this.noteId);
|
||||
}
|
||||
|
||||
return paths;
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
getSortedNotePaths(hoistedNotePath = 'root') {
|
||||
/**
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, notePath: Array<string>, isHidden: boolean}>}
|
||||
*/
|
||||
getSortedNotePathRecords(hoistedNoteId = 'root') {
|
||||
const isHoistedRoot = hoistedNoteId === 'root';
|
||||
|
||||
const notePaths = this.getAllNotePaths().map(path => ({
|
||||
notePath: path,
|
||||
isInHoistedSubTree: path.includes(hoistedNotePath),
|
||||
isArchived: path.find(noteId => froca.notes[noteId].isArchived),
|
||||
isSearch: path.find(noteId => froca.notes[noteId].type === 'search'),
|
||||
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
||||
isArchived: path.some(noteId => froca.notes[noteId].isArchived),
|
||||
isHidden: path.includes('_hidden')
|
||||
}));
|
||||
|
||||
notePaths.sort((a, b) => {
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isSearch !== b.isSearch) {
|
||||
return a.isSearch ? 1 : -1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
return a.isArchived ? 1 : -1;
|
||||
} else if (a.isHidden !== b.isHidden) {
|
||||
@@ -392,6 +387,28 @@ class FNote {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string[]} array of noteIds constituting the particular note path
|
||||
*/
|
||||
getBestNotePath(hoistedNoteId = 'root') {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId)[0]?.notePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string} serialized note path (e.g. 'root/a1h315/js725h')
|
||||
*/
|
||||
getBestNotePathString(hoistedNoteId = 'root') {
|
||||
const notePath = this.getBestNotePath(hoistedNoteId);
|
||||
|
||||
return notePath?.join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean - true if there's no non-hidden path, note is not cloned to the visible tree
|
||||
*/
|
||||
@@ -403,7 +420,7 @@ class FNote {
|
||||
for (const parentNote of this.getParentNotes()) {
|
||||
if (parentNote.noteId === 'root') {
|
||||
return false;
|
||||
} else if (parentNote.noteId === '_hidden') {
|
||||
} else if (parentNote.noteId === '_hidden' || parentNote.type === 'search') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -415,6 +432,13 @@ class FNote {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FAttribute[]} attributes
|
||||
* @param {string} type
|
||||
* @param {string} name
|
||||
* @return {FAttribute[]}
|
||||
* @private
|
||||
*/
|
||||
__filterAttrs(attributes, type, name) {
|
||||
this.__validateTypeName(type, name);
|
||||
|
||||
@@ -551,7 +575,9 @@ class FNote {
|
||||
* @returns {boolean} true if note has an attribute with given type and name (including inherited)
|
||||
*/
|
||||
hasAttribute(type, name) {
|
||||
return !!this.getAttribute(type, name);
|
||||
const attributes = this.getAttributes();
|
||||
|
||||
return attributes.some(attr => attr.name === name && attr.type === type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -619,6 +645,20 @@ class FNote {
|
||||
*/
|
||||
hasLabel(name) { return this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {boolean} true if label exists (including inherited) and does not have "false" value.
|
||||
*/
|
||||
isLabelTruthy(name) {
|
||||
const label = this.getLabel(name);
|
||||
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return label && label.value !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {boolean} true if relation exists (excluding inherited)
|
||||
@@ -730,7 +770,14 @@ class FNote {
|
||||
});
|
||||
|
||||
// attrs are not resorted if position changes after initial load
|
||||
promotedAttrs.sort((a, b) => a.position < b.position ? -1 : 1);
|
||||
promotedAttrs.sort((a, b) => {
|
||||
if (a.noteId === b.noteId) {
|
||||
return a.position < b.position ? -1 : 1;
|
||||
} else {
|
||||
// inherited promoted attributes should stay grouped: https://github.com/zadam/trilium/issues/3761
|
||||
return a.noteId < b.noteId ? -1 : 1;
|
||||
}
|
||||
});
|
||||
|
||||
return promotedAttrs;
|
||||
}
|
||||
@@ -930,7 +977,7 @@ export default FNote;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -82,7 +82,7 @@ export default FNoteComplement;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
@@ -63,36 +63,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
/** @property {dayjs} day.js library for date manipulation. See {@link https://day.js.org} for documentation */
|
||||
this.dayjs = dayjs;
|
||||
|
||||
/**
|
||||
* @property {RightPanelWidget}
|
||||
* @deprecated use api.RightPanelWidget instead
|
||||
*/
|
||||
this.CollapsibleWidget = RightPanelWidget;
|
||||
|
||||
/** @property {RightPanelWidget} */
|
||||
this.RightPanelWidget = RightPanelWidget;
|
||||
|
||||
/** @property {NoteContextAwareWidget} */
|
||||
this.NoteContextAwareWidget = NoteContextAwareWidget;
|
||||
|
||||
/**
|
||||
* @property {NoteContextAwareWidget}
|
||||
* @deprecated use NoteContextAwareWidget instead
|
||||
*/
|
||||
this.TabAwareWidget = NoteContextAwareWidget;
|
||||
|
||||
/**
|
||||
* @property {NoteContextAwareWidget}
|
||||
* @deprecated use NoteContextAwareWidget instead
|
||||
*/
|
||||
this.TabCachingWidget = NoteContextAwareWidget;
|
||||
|
||||
/**
|
||||
* @property {NoteContextAwareWidget}
|
||||
* @deprecated use NoteContextAwareWidget instead
|
||||
*/
|
||||
this.NoteContextCachingWidget = NoteContextAwareWidget;
|
||||
|
||||
/** @property {BasicWidget} */
|
||||
this.BasicWidget = BasicWidget;
|
||||
|
||||
@@ -117,7 +93,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
await ws.waitForMaxKnownEntityChangeId();
|
||||
|
||||
await appContext.tabManager.getActiveContext().setNote(notePath);
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -134,7 +110,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
await appContext.tabManager.openContextWithNote(notePath, { activate });
|
||||
|
||||
if (activate) {
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -152,10 +128,10 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
|
||||
const {ntxId} = subContexts[subContexts.length - 1];
|
||||
|
||||
appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
||||
await appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
||||
|
||||
if (activate) {
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -581,7 +557,7 @@ export default FrontendScriptApi;
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.1</a>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.2</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
|
||||
12
images/icon-black.svg
Normal file
12
images/icon-black.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="53" height="40">
|
||||
|
||||
<g transform="matrix(0.51887405 0 0 0.51887405 -30.622847 -23.349333)">
|
||||
<g>
|
||||
<path d="M139.19968 46.483948C 133.79512 46.316727 130.99477 48.84615 130.3185 49.08075C 130.93373 47.91552 131.34544 47.18139 132.91882 45.54309C 127.567184 45.48699 122.60501 46.645172 118.819 50.18706C 113.74112 54.93721 114.13588 58.872803 114.12565 58.8534C 114.12665 58.8554 113.324486 56.28694 113.083885 53.53986C 107.557976 61.18914 105.376045 71.32445 109.565636 78.88518C 112.16631 72.611374 116.29593 67.204346 121.617935 62.940678C 121.79327 58.466747 123.59313 54.686737 126.437935 51.89591C 123.87077 54.96861 122.73801 58.46922 122.8523 61.99735C 129.0425 57.37914 136.62968 54.301147 144.96371 53.29115C 138.92981 54.39993 133.4628 56.804817 128.68442 60.08495C 131.67526 61.4509 135.09087 61.66504 138.68073 60.41479C 135.23903 62.02769 131.41844 62.291573 127.55341 60.88681C 124.123 63.39894 121.072174 66.36721 118.44998 69.62935C 123.10523 71.15123 128.19724 70.83655 133.26453 68.25387C 128.6128 71.25848 123.14792 72.38525 117.30839 71.10572C 114.98041 74.22992 113.02919 77.58555 111.50413 81.04383C 113.382675 82.42883 121.53502 86.77435 135.51878 76.4623C 133.54428 75.878815 131.94408 75.053665 131.94337 75.05225C 131.98787 75.07205 133.38448 75.200424 137.46893 72.753555C 141.07997 70.64182 144.18617 66.81666 146.47923 63.839214C 144.52872 63.120605 143.00966 62.366364 143.00896 62.364605C 143.00795 62.363605 145.52956 62.534286 149.44116 59.539906C 152.93013 56.869026 156.82515 52.997295 156.83716 53.106655C 156.86186 53.129955 148.2449 46.763355 139.19968 46.483955" stroke="none" fill="#000000" fill-rule="nonzero" />
|
||||
<path d="M76.90892 60.39415C 81.01041 59.20187 83.62202 60.57837 84.18329 60.62363C 83.49581 59.85657 83.04422 59.37815 81.5362 58.43957C 85.61753 57.342182 89.62709 57.24689 93.18141 59.20068C 97.94861 61.82108 98.37924 64.89886 98.38368 64.88219C 98.38287 64.884186 98.51835 62.767998 98.19094 60.626408C 103.84037 65.368546 107.39591 72.664375 105.59999 79.25351C 102.44364 74.98344 98.27924 71.67578 93.41609 69.47424C 92.44918 66.098694 90.369 63.571594 87.674324 62.0049C 90.20933 63.84117 91.72702 66.28648 92.29676 68.9982C 86.70379 66.69781 80.32978 65.84657 73.76949 66.719246C 78.589516 66.37542 88.79929 67.0738 97.083725 73.94838C 93.808014 76.02605 89.85612 76.78993 85.50101 75.81959C 89.617004 77.19292 94.00519 76.97535 98.23167 74.84885C 100.59329 76.77167 102.71017 78.94501 104.520195 81.28075C 103.3416 82.70688 97.917564 87.62569 85.30545 82.520676C 86.70662 81.686905 87.77634 80.74236 87.77674 80.74117C 87.746544 80.76498 86.70259 81.13821 83.12366 80.07813C 79.96972 79.18005 76.88272 76.87608 74.574715 75.058075C 75.932335 74.12624 76.953674 73.25198 76.953674 73.2504C 76.95406 73.24959 75.05817 73.87652 71.50989 72.36501C 68.344666 71.016304 64.64558 68.832634 64.65687 68.918396C 64.642365 68.940994 70.04542 62.389626 76.90893 60.394146" stroke="none" fill="#000000" fill-rule="nonzero" />
|
||||
<path d="M106.35028 116.78676C 103.35939 114.0036 103.23137 111.1697 102.99563 110.68548C 102.692345 111.63276 102.514435 112.24205 102.46853 113.950066C 99.56593 111.13644 97.53256 107.88377 97.42573 103.98627C 97.2827 98.76002 99.63347 96.87469 99.61758 96.879555C 99.619576 96.879555 97.79303 97.82024 96.170654 99.15473C 97.362595 92.146484 101.699936 85.59194 108.057846 83.79309C 106.043465 88.51463 105.32079 93.58698 105.859375 98.68461C 103.522285 101.15936 102.43365 104.12773 102.44335 107.12493C 102.7356 104.12552 104.0304 101.66008 106.00902 99.8426C 106.82087 105.59001 109.21976 111.25976 113.143005 116.22528C 110.507935 112.4288 106.112755 103.67846 107.79472 93.44062C 111.1198 95.10421 113.68158 97.97678 114.99713 102.04415C 114.133644 97.97323 111.813774 94.46955 107.98454 92.04802C 108.433075 89.14839 109.210045 86.32549 110.27087 83.67378C 112.03185 83.93501 118.768524 85.95295 120.66769 98.87222C 119.291214 98.13378 117.984055 97.72311 117.98273 97.72354C 118.017624 97.73644 118.836945 98.41008 119.69913 101.88272C 120.4889 104.925644 120.07702 108.61209 119.68893 111.41583C 118.25153 110.761665 117.02649 110.35595 117.025604 110.356834C 117.024605 110.356834 118.470055 111.60574 118.94197 115.277824C 119.36268 118.55367 119.348564 122.68398 119.41433 122.632C 119.44033 122.63284 111.35593 121.44354 106.35022 116.78675" stroke="none" fill="#000000" fill-rule="nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
12
images/icon-color.svg
Normal file
12
images/icon-color.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="53" height="40">
|
||||
|
||||
<g transform="matrix(0.51887405 0 0 0.51887405 -30.622847 -23.349333)">
|
||||
<g>
|
||||
<path d="M139.19968 46.483948C 133.79512 46.316727 130.99477 48.84615 130.3185 49.08075C 130.93373 47.91552 131.34544 47.18139 132.91882 45.54309C 127.567184 45.48699 122.60501 46.645172 118.819 50.18706C 113.74112 54.93721 114.13588 58.872803 114.12565 58.8534C 114.12665 58.8554 113.324486 56.28694 113.083885 53.53986C 107.557976 61.18914 105.376045 71.32445 109.565636 78.88518C 112.16631 72.611374 116.29593 67.204346 121.617935 62.940678C 121.79327 58.466747 123.59313 54.686737 126.437935 51.89591C 123.87077 54.96861 122.73801 58.46922 122.8523 61.99735C 129.0425 57.37914 136.62968 54.301147 144.96371 53.29115C 138.92981 54.39993 133.4628 56.804817 128.68442 60.08495C 131.67526 61.4509 135.09087 61.66504 138.68073 60.41479C 135.23903 62.02769 131.41844 62.291573 127.55341 60.88681C 124.123 63.39894 121.072174 66.36721 118.44998 69.62935C 123.10523 71.15123 128.19724 70.83655 133.26453 68.25387C 128.6128 71.25848 123.14792 72.38525 117.30839 71.10572C 114.98041 74.22992 113.02919 77.58555 111.50413 81.04383C 113.382675 82.42883 121.53502 86.77435 135.51878 76.4623C 133.54428 75.878815 131.94408 75.053665 131.94337 75.05225C 131.98787 75.07205 133.38448 75.200424 137.46893 72.753555C 141.07997 70.64182 144.18617 66.81666 146.47923 63.839214C 144.52872 63.120605 143.00966 62.366364 143.00896 62.364605C 143.00795 62.363605 145.52956 62.534286 149.44116 59.539906C 152.93013 56.869026 156.82515 52.997295 156.83716 53.106655C 156.86186 53.129955 148.2449 46.763355 139.19968 46.483955" stroke="none" fill="#4FA52B" fill-rule="nonzero" />
|
||||
<path d="M76.90892 60.39415C 81.01041 59.20187 83.62202 60.57837 84.18329 60.62363C 83.49581 59.85657 83.04422 59.37815 81.5362 58.43957C 85.61753 57.342182 89.62709 57.24689 93.18141 59.20068C 97.94861 61.82108 98.37924 64.89886 98.38368 64.88219C 98.38287 64.884186 98.51835 62.767998 98.19094 60.626408C 103.84037 65.368546 107.39591 72.664375 105.59999 79.25351C 102.44364 74.98344 98.27924 71.67578 93.41609 69.47424C 92.44918 66.098694 90.369 63.571594 87.674324 62.0049C 90.20933 63.84117 91.72702 66.28648 92.29676 68.9982C 86.70379 66.69781 80.32978 65.84657 73.76949 66.719246C 78.589516 66.37542 88.79929 67.0738 97.083725 73.94838C 93.808014 76.02605 89.85612 76.78993 85.50101 75.81959C 89.617004 77.19292 94.00519 76.97535 98.23167 74.84885C 100.59329 76.77167 102.71017 78.94501 104.520195 81.28075C 103.3416 82.70688 97.917564 87.62569 85.30545 82.520676C 86.70662 81.686905 87.77634 80.74236 87.77674 80.74117C 87.746544 80.76498 86.70259 81.13821 83.12366 80.07813C 79.96972 79.18005 76.88272 76.87608 74.574715 75.058075C 75.932335 74.12624 76.953674 73.25198 76.953674 73.2504C 76.95406 73.24959 75.05817 73.87652 71.50989 72.36501C 68.344666 71.016304 64.64558 68.832634 64.65687 68.918396C 64.642365 68.940994 70.04542 62.389626 76.90893 60.394146" stroke="none" fill="#E47B19" fill-rule="nonzero" />
|
||||
<path d="M106.35028 116.78676C 103.35939 114.0036 103.23137 111.1697 102.99563 110.68548C 102.692345 111.63276 102.514435 112.24205 102.46853 113.950066C 99.56593 111.13644 97.53256 107.88377 97.42573 103.98627C 97.2827 98.76002 99.63347 96.87469 99.61758 96.879555C 99.619576 96.879555 97.79303 97.82024 96.170654 99.15473C 97.362595 92.146484 101.699936 85.59194 108.057846 83.79309C 106.043465 88.51463 105.32079 93.58698 105.859375 98.68461C 103.522285 101.15936 102.43365 104.12773 102.44335 107.12493C 102.7356 104.12552 104.0304 101.66008 106.00902 99.8426C 106.82087 105.59001 109.21976 111.25976 113.143005 116.22528C 110.507935 112.4288 106.112755 103.67846 107.79472 93.44062C 111.1198 95.10421 113.68158 97.97678 114.99713 102.04415C 114.133644 97.97323 111.813774 94.46955 107.98454 92.04802C 108.433075 89.14839 109.210045 86.32549 110.27087 83.67378C 112.03185 83.93501 118.768524 85.95295 120.66769 98.87222C 119.291214 98.13378 117.984055 97.72311 117.98273 97.72354C 118.017624 97.73644 118.836945 98.41008 119.69913 101.88272C 120.4889 104.925644 120.07702 108.61209 119.68893 111.41583C 118.25153 110.761665 117.02649 110.35595 117.025604 110.356834C 117.024605 110.356834 118.470055 111.60574 118.94197 115.277824C 119.36268 118.55367 119.348564 122.68398 119.41433 122.632C 119.44033 122.63284 111.35593 121.44354 106.35022 116.78675" stroke="none" fill="#E33F3B" fill-rule="nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
12
images/icon-grey.svg
Normal file
12
images/icon-grey.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="53" height="40">
|
||||
|
||||
<g transform="matrix(0.51887405 0 0 0.51887405 -30.622847 -23.349333)">
|
||||
<g>
|
||||
<path d="M139.19968 46.483948C 133.79512 46.316727 130.99477 48.84615 130.3185 49.08075C 130.93373 47.91552 131.34544 47.18139 132.91882 45.54309C 127.567184 45.48699 122.60501 46.645172 118.819 50.18706C 113.74112 54.93721 114.13588 58.872803 114.12565 58.8534C 114.12665 58.8554 113.324486 56.28694 113.083885 53.53986C 107.557976 61.18914 105.376045 71.32445 109.565636 78.88518C 112.16631 72.611374 116.29593 67.204346 121.617935 62.940678C 121.79327 58.466747 123.59313 54.686737 126.437935 51.89591C 123.87077 54.96861 122.73801 58.46922 122.8523 61.99735C 129.0425 57.37914 136.62968 54.301147 144.96371 53.29115C 138.92981 54.39993 133.4628 56.804817 128.68442 60.08495C 131.67526 61.4509 135.09087 61.66504 138.68073 60.41479C 135.23903 62.02769 131.41844 62.291573 127.55341 60.88681C 124.123 63.39894 121.072174 66.36721 118.44998 69.62935C 123.10523 71.15123 128.19724 70.83655 133.26453 68.25387C 128.6128 71.25848 123.14792 72.38525 117.30839 71.10572C 114.98041 74.22992 113.02919 77.58555 111.50413 81.04383C 113.382675 82.42883 121.53502 86.77435 135.51878 76.4623C 133.54428 75.878815 131.94408 75.053665 131.94337 75.05225C 131.98787 75.07205 133.38448 75.200424 137.46893 72.753555C 141.07997 70.64182 144.18617 66.81666 146.47923 63.839214C 144.52872 63.120605 143.00966 62.366364 143.00896 62.364605C 143.00795 62.363605 145.52956 62.534286 149.44116 59.539906C 152.93013 56.869026 156.82515 52.997295 156.83716 53.106655C 156.86186 53.129955 148.2449 46.763355 139.19968 46.483955" stroke="none" fill="#ABABAB" fill-rule="nonzero" />
|
||||
<path d="M76.90892 60.39415C 81.01041 59.20187 83.62202 60.57837 84.18329 60.62363C 83.49581 59.85657 83.04422 59.37815 81.5362 58.43957C 85.61753 57.342182 89.62709 57.24689 93.18141 59.20068C 97.94861 61.82108 98.37924 64.89886 98.38368 64.88219C 98.38287 64.884186 98.51835 62.767998 98.19094 60.626408C 103.84037 65.368546 107.39591 72.664375 105.59999 79.25351C 102.44364 74.98344 98.27924 71.67578 93.41609 69.47424C 92.44918 66.098694 90.369 63.571594 87.674324 62.0049C 90.20933 63.84117 91.72702 66.28648 92.29676 68.9982C 86.70379 66.69781 80.32978 65.84657 73.76949 66.719246C 78.589516 66.37542 88.79929 67.0738 97.083725 73.94838C 93.808014 76.02605 89.85612 76.78993 85.50101 75.81959C 89.617004 77.19292 94.00519 76.97535 98.23167 74.84885C 100.59329 76.77167 102.71017 78.94501 104.520195 81.28075C 103.3416 82.70688 97.917564 87.62569 85.30545 82.520676C 86.70662 81.686905 87.77634 80.74236 87.77674 80.74117C 87.746544 80.76498 86.70259 81.13821 83.12366 80.07813C 79.96972 79.18005 76.88272 76.87608 74.574715 75.058075C 75.932335 74.12624 76.953674 73.25198 76.953674 73.2504C 76.95406 73.24959 75.05817 73.87652 71.50989 72.36501C 68.344666 71.016304 64.64558 68.832634 64.65687 68.918396C 64.642365 68.940994 70.04542 62.389626 76.90893 60.394146" stroke="none" fill="#ABABAB" fill-rule="nonzero" />
|
||||
<path d="M106.35028 116.78676C 103.35939 114.0036 103.23137 111.1697 102.99563 110.68548C 102.692345 111.63276 102.514435 112.24205 102.46853 113.950066C 99.56593 111.13644 97.53256 107.88377 97.42573 103.98627C 97.2827 98.76002 99.63347 96.87469 99.61758 96.879555C 99.619576 96.879555 97.79303 97.82024 96.170654 99.15473C 97.362595 92.146484 101.699936 85.59194 108.057846 83.79309C 106.043465 88.51463 105.32079 93.58698 105.859375 98.68461C 103.522285 101.15936 102.43365 104.12773 102.44335 107.12493C 102.7356 104.12552 104.0304 101.66008 106.00902 99.8426C 106.82087 105.59001 109.21976 111.25976 113.143005 116.22528C 110.507935 112.4288 106.112755 103.67846 107.79472 93.44062C 111.1198 95.10421 113.68158 97.97678 114.99713 102.04415C 114.133644 97.97323 111.813774 94.46955 107.98454 92.04802C 108.433075 89.14839 109.210045 86.32549 110.27087 83.67378C 112.03185 83.93501 118.768524 85.95295 120.66769 98.87222C 119.291214 98.13378 117.984055 97.72311 117.98273 97.72354C 118.017624 97.73644 118.836945 98.41008 119.69913 101.88272C 120.4889 104.925644 120.07702 108.61209 119.68893 111.41583C 118.25153 110.761665 117.02649 110.35595 117.025604 110.356834C 117.024605 110.356834 118.470055 111.60574 118.94197 115.277824C 119.36268 118.55367 119.348564 122.68398 119.41433 122.632C 119.44033 122.63284 111.35593 121.44354 106.35022 116.78675" stroke="none" fill="#ABABAB" fill-rule="nonzero" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
4
libraries/ckeditor/ckeditor.js
vendored
4
libraries/ckeditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
libraries/codemirror/addon/lint/eslint.js
vendored
2
libraries/codemirror/addon/lint/eslint.js
vendored
@@ -46,7 +46,7 @@
|
||||
const errors = new eslint().verify(text, {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
ecmaVersion: 2019
|
||||
ecmaVersion: 2022
|
||||
},
|
||||
extends: ['eslint:recommended', 'airbnb-base'],
|
||||
env: {
|
||||
|
||||
13
nodemon.json
Normal file
13
nodemon.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"restartable": "rs",
|
||||
"ignore": [".git", "node_modules/**/node_modules", "src/public/"],
|
||||
"verbose": false,
|
||||
"execMap": {
|
||||
"js": "node --harmony"
|
||||
},
|
||||
"watch": ["src/"],
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"ext": "js,json"
|
||||
}
|
||||
6445
package-lock.json
generated
6445
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.59.0-beta",
|
||||
"version": "0.60.3",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -13,20 +13,22 @@
|
||||
"url": "https://github.com/zadam/trilium.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 node ./src/www",
|
||||
"start-server-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 node ./src/www",
|
||||
"start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon ./src/www",
|
||||
"start-server-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 nodemon ./src/www",
|
||||
"start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .",
|
||||
"start-electron-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 electron --inspect=5858 .",
|
||||
"switch-server": "rm -rf ./node_modules/better-sqlite3 && npm install",
|
||||
"switch-electron": "rm -rf ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild",
|
||||
"switch-electron": "./node_modules/.bin/electron-rebuild",
|
||||
"build-backend-docs": "rm -rf ./docs/backend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/becca/entities/*.js src/services/backend_script_api.js src/services/sql.js",
|
||||
"build-frontend-docs": "rm -rf ./docs/frontend_api && ./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/right_panel_widget.js",
|
||||
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
||||
"webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js",
|
||||
"webpack": "webpack -c webpack.config.js",
|
||||
"test-jasmine": "jasmine",
|
||||
"test-es6": "node -r esm spec-es6/attribute_parser.spec.js ",
|
||||
"test": "npm run test-jasmine && npm run test-es6",
|
||||
"postinstall": "rimraf ./node_modules/canvas"
|
||||
"postinstall": "rimraf ./node_modules/canvas",
|
||||
"lint": "eslint . --cache",
|
||||
"prepare": "husky install || echo 'Husky install failed, expected on flatpak build'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "6.0.2",
|
||||
@@ -34,7 +36,7 @@
|
||||
"@excalidraw/excalidraw": "0.14.2",
|
||||
"archiver": "5.3.1",
|
||||
"async-mutex": "0.4.0",
|
||||
"axios": "1.3.3",
|
||||
"axios": "1.4.0",
|
||||
"better-sqlite3": "7.4.5",
|
||||
"chokidar": "3.5.3",
|
||||
"cls-hooked": "4.2.2",
|
||||
@@ -43,19 +45,19 @@
|
||||
"cookie-parser": "1.4.6",
|
||||
"csurf": "1.11.0",
|
||||
"dayjs": "1.11.7",
|
||||
"dayjs-plugin-utc": "^0.1.2",
|
||||
"debounce": "^1.2.1",
|
||||
"ejs": "3.1.8",
|
||||
"dayjs-plugin-utc": "0.1.2",
|
||||
"debounce": "1.2.1",
|
||||
"ejs": "3.1.9",
|
||||
"electron-debug": "3.2.0",
|
||||
"electron-dl": "3.5.0",
|
||||
"electron-window-state": "5.0.3",
|
||||
"escape-html": "^1.0.3",
|
||||
"escape-html": "1.0.3",
|
||||
"express": "4.18.2",
|
||||
"express-partial-content": "1.0.2",
|
||||
"express-rate-limit": "6.7.0",
|
||||
"express-session": "1.17.3",
|
||||
"fs-extra": "11.1.0",
|
||||
"helmet": "6.0.1",
|
||||
"fs-extra": "11.1.1",
|
||||
"helmet": "6.1.2",
|
||||
"html": "1.0.0",
|
||||
"html2plaintext": "2.1.4",
|
||||
"http-proxy-agent": "5.0.0",
|
||||
@@ -64,33 +66,33 @@
|
||||
"ini": "3.0.1",
|
||||
"is-animated": "2.0.2",
|
||||
"is-svg": "4.3.2",
|
||||
"jimp": "0.22.4",
|
||||
"jimp": "0.22.7",
|
||||
"joplin-turndown-plugin-gfm": "1.0.12",
|
||||
"jsdom": "21.1.0",
|
||||
"jsdom": "21.1.1",
|
||||
"mime-types": "2.1.35",
|
||||
"multer": "1.4.5-lts.1",
|
||||
"node-abi": "3.33.0",
|
||||
"node-abi": "3.40.0",
|
||||
"normalize-strings": "1.1.1",
|
||||
"open": "8.4.1",
|
||||
"rand-token": "1.0.1",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"request": "2.88.2",
|
||||
"rimraf": "3.0.2",
|
||||
"rimraf": "5.0.1",
|
||||
"safe-compare": "1.1.4",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"sanitize-html": "2.9.0",
|
||||
"sanitize-html": "2.10.0",
|
||||
"sax": "1.2.4",
|
||||
"semver": "7.3.8",
|
||||
"semver": "7.5.1",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.5.0",
|
||||
"stream-throttle": "0.1.3",
|
||||
"striptags": "3.2.0",
|
||||
"tmp": "0.2.1",
|
||||
"turndown": "7.1.1",
|
||||
"turndown": "7.1.2",
|
||||
"unescape": "1.0.1",
|
||||
"ws": "8.12.1",
|
||||
"xml2js": "0.4.23",
|
||||
"ws": "8.13.0",
|
||||
"xml2js": "0.6.0",
|
||||
"yauzl": "2.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -99,15 +101,29 @@
|
||||
"electron-builder": "23.6.0",
|
||||
"electron-packager": "17.1.1",
|
||||
"electron-rebuild": "3.2.9",
|
||||
"eslint": "8.38.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-config-prettier": "8.8.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsonc": "2.8.0",
|
||||
"eslint-plugin-prettier": "4.2.1",
|
||||
"esm": "3.2.25",
|
||||
"jasmine": "4.5.0",
|
||||
"jsdoc": "4.0.1",
|
||||
"husky": "8.0.3",
|
||||
"jsonc-eslint-parser": "2.3.0",
|
||||
"lint-staged": "13.2.2",
|
||||
"jasmine": "4.6.0",
|
||||
"jsdoc": "4.0.2",
|
||||
"lorem-ipsum": "2.0.8",
|
||||
"prettier": "2.8.8",
|
||||
"nodemon": "2.0.22",
|
||||
"rcedit": "3.0.1",
|
||||
"webpack": "5.75.0",
|
||||
"webpack-cli": "5.0.1"
|
||||
"webpack": "5.84.1",
|
||||
"webpack-cli": "5.1.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"electron-installer-debian": "3.1.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": "eslint --cache --fix"
|
||||
}
|
||||
}
|
||||
|
||||
33
src/app.js
33
src/app.js
@@ -5,12 +5,13 @@ const favicon = require('serve-favicon');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const helmet = require('helmet');
|
||||
const session = require('express-session');
|
||||
const compression = require('compression')
|
||||
const compression = require('compression');
|
||||
const FileStore = require('session-file-store')(session);
|
||||
const sessionSecret = require('./services/session_secret');
|
||||
const dataDir = require('./services/data_dir');
|
||||
const utils = require('./services/utils');
|
||||
const assetPath = require('./services/asset_path');
|
||||
const env = require('./services/env');
|
||||
require('./services/handlers');
|
||||
require('./becca/becca_loader');
|
||||
|
||||
@@ -30,27 +31,37 @@ app.use(helmet({
|
||||
crossOriginEmbedderPolicy: false
|
||||
}));
|
||||
|
||||
const persistentCacheStatic = (root, options) => {
|
||||
if (!env.isDev()) {
|
||||
options = {
|
||||
maxAge: '1y',
|
||||
...options
|
||||
};
|
||||
}
|
||||
return express.static(root, options);
|
||||
};
|
||||
|
||||
app.use(express.text({limit: '500mb'}));
|
||||
app.use(express.json({limit: '500mb'}));
|
||||
app.use(express.raw({limit: '500mb'}));
|
||||
app.use(express.urlencoded({extended: false}));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, 'public/root')));
|
||||
app.use(`/${assetPath}/app`, express.static(path.join(__dirname, 'public/app')));
|
||||
app.use(`/${assetPath}/app-dist`, express.static(path.join(__dirname, 'public/app-dist')));
|
||||
app.use(`/${assetPath}/fonts`, express.static(path.join(__dirname, 'public/fonts')));
|
||||
app.use(`/${assetPath}/app`, persistentCacheStatic(path.join(__dirname, 'public/app')));
|
||||
app.use(`/${assetPath}/app-dist`, persistentCacheStatic(path.join(__dirname, 'public/app-dist')));
|
||||
app.use(`/${assetPath}/fonts`, persistentCacheStatic(path.join(__dirname, 'public/fonts')));
|
||||
app.use(`/assets/vX/fonts`, express.static(path.join(__dirname, 'public/fonts')));
|
||||
app.use(`/${assetPath}/stylesheets`, express.static(path.join(__dirname, 'public/stylesheets')));
|
||||
app.use(`/${assetPath}/stylesheets`, persistentCacheStatic(path.join(__dirname, 'public/stylesheets')));
|
||||
app.use(`/assets/vX/stylesheets`, express.static(path.join(__dirname, 'public/stylesheets')));
|
||||
app.use(`/${assetPath}/libraries`, express.static(path.join(__dirname, '..', 'libraries')));
|
||||
app.use(`/${assetPath}/libraries`, persistentCacheStatic(path.join(__dirname, '..', 'libraries')));
|
||||
app.use(`/assets/vX/libraries`, express.static(path.join(__dirname, '..', 'libraries')));
|
||||
// excalidraw-view mode in shared notes
|
||||
app.use(`/${assetPath}/node_modules/react/umd/react.production.min.js`, express.static(path.join(__dirname, '..', 'node_modules/react/umd/react.production.min.js')));
|
||||
app.use(`/${assetPath}/node_modules/react-dom/umd/react-dom.production.min.js`, express.static(path.join(__dirname, '..', 'node_modules/react-dom/umd/react-dom.production.min.js')));
|
||||
app.use(`/${assetPath}/node_modules/react/umd/react.production.min.js`, persistentCacheStatic(path.join(__dirname, '..', 'node_modules/react/umd/react.production.min.js')));
|
||||
app.use(`/${assetPath}/node_modules/react-dom/umd/react-dom.production.min.js`, persistentCacheStatic(path.join(__dirname, '..', 'node_modules/react-dom/umd/react-dom.production.min.js')));
|
||||
// expose whole dist folder since complete assets are needed in edit and share
|
||||
app.use(`/node_modules/@excalidraw/excalidraw/dist/`, express.static(path.join(__dirname, '..', 'node_modules/@excalidraw/excalidraw/dist/')));
|
||||
app.use(`/${assetPath}/node_modules/@excalidraw/excalidraw/dist/`, express.static(path.join(__dirname, '..', 'node_modules/@excalidraw/excalidraw/dist/')));
|
||||
app.use(`/${assetPath}/images`, express.static(path.join(__dirname, '..', 'images')));
|
||||
app.use(`/${assetPath}/node_modules/@excalidraw/excalidraw/dist/`, persistentCacheStatic(path.join(__dirname, '..', 'node_modules/@excalidraw/excalidraw/dist/')));
|
||||
app.use(`/${assetPath}/images`, persistentCacheStatic(path.join(__dirname, '..', 'images')));
|
||||
app.use(`/assets/vX/images`, express.static(path.join(__dirname, '..', 'images')));
|
||||
app.use(`/manifest.webmanifest`, express.static(path.join(__dirname, 'public/manifest.webmanifest')));
|
||||
app.use(`/robots.txt`, express.static(path.join(__dirname, 'public/robots.txt')));
|
||||
@@ -61,7 +72,7 @@ const sessionParser = session({
|
||||
cookie: {
|
||||
// path: "/",
|
||||
httpOnly: true,
|
||||
maxAge: 24 * 60 * 60 * 1000 // in milliseconds
|
||||
maxAge: 24 * 60 * 60 * 1000 // in milliseconds
|
||||
},
|
||||
name: 'trilium.sid',
|
||||
store: new FileStore({
|
||||
|
||||
@@ -69,22 +69,12 @@ function reload() {
|
||||
require('../services/ws').reloadFrontend();
|
||||
}
|
||||
|
||||
function postProcessEntityUpdate(entityName, entity) {
|
||||
if (entityName === 'branches') {
|
||||
branchUpdated(entity);
|
||||
} else if (entityName === 'attributes') {
|
||||
attributeUpdated(entity);
|
||||
} else if (entityName === 'note_reordering') {
|
||||
noteReorderingUpdated(entity);
|
||||
}
|
||||
}
|
||||
|
||||
eventService.subscribeBeccaLoader([eventService.ENTITY_CHANGE_SYNCED], ({entityName, entityRow}) => {
|
||||
if (!becca.loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (["notes", "branches", "attributes", "etapi_tokens"].includes(entityName)) {
|
||||
if (["notes", "branches", "attributes", "etapi_tokens", "options"].includes(entityName)) {
|
||||
const EntityClass = entityConstructor.getEntityFromEntityName(entityName);
|
||||
const primaryKeyName = EntityClass.primaryKeyName;
|
||||
|
||||
@@ -110,6 +100,25 @@ eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({entityName, en
|
||||
postProcessEntityUpdate(entityName, entity);
|
||||
});
|
||||
|
||||
/**
|
||||
* This gets run on entity being created or updated.
|
||||
*
|
||||
* @param entityName
|
||||
* @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync).
|
||||
* Should be therefore treated as a row.
|
||||
*/
|
||||
function postProcessEntityUpdate(entityName, entityRow) {
|
||||
if (entityName === 'notes') {
|
||||
noteUpdated(entityRow);
|
||||
} else if (entityName === 'branches') {
|
||||
branchUpdated(entityRow);
|
||||
} else if (entityName === 'attributes') {
|
||||
attributeUpdated(entityRow);
|
||||
} else if (entityName === 'note_reordering') {
|
||||
noteReorderingUpdated(entityRow);
|
||||
}
|
||||
}
|
||||
|
||||
eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED], ({entityName, entityId}) => {
|
||||
if (!becca.loaded) {
|
||||
return;
|
||||
@@ -147,6 +156,7 @@ function branchDeleted(branchId) {
|
||||
.filter(parentBranch => parentBranch.branchId !== branch.branchId);
|
||||
|
||||
if (childNote.parents.length > 0) {
|
||||
// subtree notes might lose some inherited attributes
|
||||
childNote.invalidateSubTree();
|
||||
}
|
||||
}
|
||||
@@ -161,15 +171,28 @@ function branchDeleted(branchId) {
|
||||
delete becca.branches[branch.branchId];
|
||||
}
|
||||
|
||||
function branchUpdated(branch) {
|
||||
const childNote = becca.notes[branch.noteId];
|
||||
function noteUpdated(entityRow) {
|
||||
const note = becca.notes[entityRow.noteId];
|
||||
|
||||
if (note) {
|
||||
// type / mime could have been changed, and they are present in flatTextCache
|
||||
note.flatTextCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
function branchUpdated(branchRow) {
|
||||
const childNote = becca.notes[branchRow.noteId];
|
||||
|
||||
if (childNote) {
|
||||
childNote.flatTextCache = null;
|
||||
childNote.sortParents();
|
||||
|
||||
// notes in the subtree can get new inherited attributes
|
||||
// this is in theory needed upon branch creation, but there's no create event for sync changes
|
||||
childNote.invalidateSubTree();
|
||||
}
|
||||
|
||||
const parentNote = becca.notes[branch.parentNoteId];
|
||||
const parentNote = becca.notes[branchRow.parentNoteId];
|
||||
|
||||
if (parentNote) {
|
||||
parentNote.sortChildren();
|
||||
@@ -211,8 +234,10 @@ function attributeDeleted(attributeId) {
|
||||
}
|
||||
}
|
||||
|
||||
function attributeUpdated(attribute) {
|
||||
const note = becca.notes[attribute.noteId];
|
||||
/** @param {BAttribute} attributeRow */
|
||||
function attributeUpdated(attributeRow) {
|
||||
const attribute = becca.attributes[attributeRow.attributeId];
|
||||
const note = becca.notes[attributeRow.noteId];
|
||||
|
||||
if (note) {
|
||||
if (attribute.isAffectingSubtree || note.isInherited()) {
|
||||
|
||||
@@ -24,49 +24,12 @@ function isNotePathArchived(notePath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This assumes that note is available. "archived" note means that there isn't a single non-archived note-path
|
||||
* leading to this note.
|
||||
*
|
||||
* @param noteId
|
||||
*/
|
||||
function isArchived(noteId) {
|
||||
const notePath = getSomePath(noteId);
|
||||
|
||||
return isNotePathArchived(notePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} noteId
|
||||
* @param {string} ancestorNoteId
|
||||
* @returns {boolean} - true if given noteId has ancestorNoteId in any of its paths (even archived)
|
||||
*/
|
||||
function isInAncestor(noteId, ancestorNoteId) {
|
||||
if (ancestorNoteId === 'root' || ancestorNoteId === noteId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const note = becca.notes[noteId];
|
||||
|
||||
if (!note) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const parentNote of note.parents) {
|
||||
if (isInAncestor(parentNote.noteId, ancestorNoteId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNoteTitle(childNoteId, parentNoteId) {
|
||||
const childNote = becca.notes[childNoteId];
|
||||
const parentNote = becca.notes[parentNoteId];
|
||||
|
||||
if (!childNote) {
|
||||
log.info(`Cannot find note in cache for noteId '${childNoteId}'`);
|
||||
log.info(`Cannot find note '${childNoteId}'`);
|
||||
return "[error fetching title]";
|
||||
}
|
||||
|
||||
@@ -119,99 +82,8 @@ function getNoteTitleForPath(notePathArray) {
|
||||
return titles.join(' / ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns notePath for noteId from cache. Note hoisting is respected.
|
||||
* Archived (and hidden) notes are also returned, but non-archived paths are preferred if available
|
||||
* - this means that archived paths is returned only if there's no non-archived path
|
||||
* - you can check whether returned path is archived using isArchived
|
||||
*/
|
||||
function getSomePath(note, path = []) {
|
||||
// first try to find note within hoisted note, otherwise take any existing note path
|
||||
// each branch needs a separate copy since it's mutable
|
||||
return getSomePathInner(note, [...path], true)
|
||||
|| getSomePathInner(note, [...path], false);
|
||||
}
|
||||
|
||||
function getSomePathInner(note, path, respectHoisting) {
|
||||
if (note.isRoot()) {
|
||||
path.push(note.noteId);
|
||||
path.reverse();
|
||||
|
||||
if (respectHoisting && !path.includes(cls.getHoistedNoteId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const parents = note.parents;
|
||||
if (parents.length === 0) {
|
||||
console.log(`Note ${note.noteId} - "${note.title}" has no parents.`);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const parentNote of parents) {
|
||||
const retPath = getSomePathInner(parentNote, path.concat([note.noteId]), respectHoisting);
|
||||
|
||||
if (retPath) {
|
||||
return retPath;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNotePath(noteId) {
|
||||
const note = becca.notes[noteId];
|
||||
|
||||
if (!note) {
|
||||
console.trace(`Cannot find note '${noteId}' in cache.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const retPath = getSomePath(note);
|
||||
|
||||
if (retPath) {
|
||||
const noteTitle = getNoteTitleForPath(retPath);
|
||||
|
||||
let branchId;
|
||||
|
||||
if (note.isRoot()) {
|
||||
branchId = 'none_root';
|
||||
}
|
||||
else {
|
||||
const parentNote = note.parents[0];
|
||||
branchId = becca.getBranchFromChildAndParent(noteId, parentNote.noteId).branchId;
|
||||
}
|
||||
|
||||
return {
|
||||
noteId: noteId,
|
||||
branchId: branchId,
|
||||
title: noteTitle,
|
||||
notePath: retPath,
|
||||
path: retPath.join('/')
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param noteId
|
||||
* @returns {boolean} - true if note exists (is not deleted) and is available in current note hoisting
|
||||
*/
|
||||
function isAvailable(noteId) {
|
||||
const notePath = getNotePath(noteId);
|
||||
|
||||
return !!notePath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSomePath,
|
||||
getNotePath,
|
||||
getNoteTitle,
|
||||
getNoteTitleForPath,
|
||||
isAvailable,
|
||||
isArchived,
|
||||
isInAncestor,
|
||||
isNotePathArchived
|
||||
};
|
||||
|
||||
@@ -96,7 +96,7 @@ class BAttribute extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
if (this.type === 'relation' && !(this.value in this.becca.notes)) {
|
||||
throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it target not existing note '${this.value}'.`);
|
||||
throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it targets not existing note '${this.value}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const TaskContext = require("../../services/task_context");
|
||||
const dayjs = require("dayjs");
|
||||
const utc = require('dayjs/plugin/utc');
|
||||
const eventService = require("../../services/events");
|
||||
const cls = require("../../services/cls.js");
|
||||
dayjs.extend(utc);
|
||||
|
||||
const LABEL = 'label';
|
||||
@@ -84,7 +85,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
this.decrypt();
|
||||
|
||||
/** @type {string|null} */
|
||||
this.flatTextCache = null;
|
||||
this.__flatTextCache = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -97,7 +98,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
* @private */
|
||||
this.parents = [];
|
||||
/** @type {BNote[]}
|
||||
* @private*/
|
||||
* @private */
|
||||
this.children = [];
|
||||
/** @type {BAttribute[]}
|
||||
* @private */
|
||||
@@ -107,18 +108,18 @@ class BNote extends AbstractBeccaEntity {
|
||||
* @private */
|
||||
this.__attributeCache = null;
|
||||
/** @type {BAttribute[]|null}
|
||||
* @private*/
|
||||
this.inheritableAttributeCache = null;
|
||||
* @private */
|
||||
this.__inheritableAttributeCache = null;
|
||||
|
||||
/** @type {BAttribute[]}
|
||||
* @private*/
|
||||
* @private */
|
||||
this.targetRelations = [];
|
||||
|
||||
this.becca.addNote(this.noteId, this);
|
||||
|
||||
/** @type {BNote[]|null}
|
||||
* @private */
|
||||
this.ancestorCache = null;
|
||||
this.__ancestorCache = null;
|
||||
|
||||
// following attributes are filled during searching from database
|
||||
|
||||
@@ -316,10 +317,12 @@ class BNote extends AbstractBeccaEntity {
|
||||
isSynced: true
|
||||
});
|
||||
|
||||
eventService.emit(eventService.ENTITY_CHANGED, {
|
||||
entityName: 'note_contents',
|
||||
entity: this
|
||||
});
|
||||
if (!cls.isEntityEventsDisabled()) {
|
||||
eventService.emit(eventService.ENTITY_CHANGED, {
|
||||
entityName: 'note_contents',
|
||||
entity: this
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setJsonContent(content) {
|
||||
@@ -454,11 +457,11 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
}
|
||||
|
||||
this.inheritableAttributeCache = [];
|
||||
this.__inheritableAttributeCache = [];
|
||||
|
||||
for (const attr of this.__attributeCache) {
|
||||
if (attr.isInheritable) {
|
||||
this.inheritableAttributeCache.push(attr);
|
||||
this.__inheritableAttributeCache.push(attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,11 +478,11 @@ class BNote extends AbstractBeccaEntity {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!this.inheritableAttributeCache) {
|
||||
this.__getAttributes(path); // will refresh also this.inheritableAttributeCache
|
||||
if (!this.__inheritableAttributeCache) {
|
||||
this.__getAttributes(path); // will refresh also this.__inheritableAttributeCache
|
||||
}
|
||||
|
||||
return this.inheritableAttributeCache;
|
||||
return this.__inheritableAttributeCache;
|
||||
}
|
||||
|
||||
__validateTypeName(type, name) {
|
||||
@@ -532,6 +535,20 @@ class BNote extends AbstractBeccaEntity {
|
||||
*/
|
||||
hasLabel(name, value) { return this.hasAttribute(LABEL, name, value); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {boolean} true if label exists (including inherited) and does not have "false" value.
|
||||
*/
|
||||
isLabelTruthy(name) {
|
||||
const label = this.getLabel(name);
|
||||
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return label && label.value !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @param {string} [value] - label value
|
||||
@@ -733,6 +750,21 @@ class BNote extends AbstractBeccaEntity {
|
||||
return this.hasAttribute('label', 'archived');
|
||||
}
|
||||
|
||||
areAllNotePathsArchived() {
|
||||
// there's a slight difference between note being itself archived and all its note paths being archived
|
||||
// - note is archived when it itself has an archived label or inherits it
|
||||
// - note does not have or inherit archived label, but each note paths contains a note with (non-inheritable)
|
||||
// archived label
|
||||
|
||||
const bestNotePathRecord = this.getSortedNotePathRecords()[0];
|
||||
|
||||
if (!bestNotePathRecord) {
|
||||
throw new Error(`No note path available for note '${this.noteId}'`);
|
||||
}
|
||||
|
||||
return bestNotePathRecord.isArchived;
|
||||
}
|
||||
|
||||
hasInheritableArchivedLabel() {
|
||||
for (const attr of this.getAttributes()) {
|
||||
if (attr.name === 'archived' && attr.type === LABEL && attr.isInheritable) {
|
||||
@@ -784,40 +816,40 @@ class BNote extends AbstractBeccaEntity {
|
||||
* @returns {string} - returns flattened textual representation of note, prefixes and attributes
|
||||
*/
|
||||
getFlatText() {
|
||||
if (!this.flatTextCache) {
|
||||
this.flatTextCache = `${this.noteId} ${this.type} ${this.mime} `;
|
||||
if (!this.__flatTextCache) {
|
||||
this.__flatTextCache = `${this.noteId} ${this.type} ${this.mime} `;
|
||||
|
||||
for (const branch of this.parentBranches) {
|
||||
if (branch.prefix) {
|
||||
this.flatTextCache += `${branch.prefix} `;
|
||||
this.__flatTextCache += `${branch.prefix} `;
|
||||
}
|
||||
}
|
||||
|
||||
this.flatTextCache += `${this.title} `;
|
||||
this.__flatTextCache += `${this.title} `;
|
||||
|
||||
for (const attr of this.getAttributes()) {
|
||||
// it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
|
||||
this.flatTextCache += `${attr.type === 'label' ? '#' : '~'}${attr.name}`;
|
||||
this.__flatTextCache += `${attr.type === 'label' ? '#' : '~'}${attr.name}`;
|
||||
|
||||
if (attr.value) {
|
||||
this.flatTextCache += `=${attr.value}`;
|
||||
this.__flatTextCache += `=${attr.value}`;
|
||||
}
|
||||
|
||||
this.flatTextCache += ' ';
|
||||
this.__flatTextCache += ' ';
|
||||
}
|
||||
|
||||
this.flatTextCache = utils.normalize(this.flatTextCache);
|
||||
this.__flatTextCache = utils.normalize(this.__flatTextCache);
|
||||
}
|
||||
|
||||
return this.flatTextCache;
|
||||
return this.__flatTextCache;
|
||||
}
|
||||
|
||||
invalidateThisCache() {
|
||||
this.flatTextCache = null;
|
||||
this.__flatTextCache = null;
|
||||
|
||||
this.__attributeCache = null;
|
||||
this.inheritableAttributeCache = null;
|
||||
this.ancestorCache = null;
|
||||
this.__inheritableAttributeCache = null;
|
||||
this.__ancestorCache = null;
|
||||
}
|
||||
|
||||
invalidateSubTree(path = []) {
|
||||
@@ -846,24 +878,6 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
}
|
||||
|
||||
invalidateSubtreeFlatText() {
|
||||
this.flatTextCache = null;
|
||||
|
||||
for (const childNote of this.children) {
|
||||
childNote.invalidateSubtreeFlatText();
|
||||
}
|
||||
|
||||
for (const targetRelation of this.targetRelations) {
|
||||
if (targetRelation.name === 'template' || targetRelation.name === 'inherit') {
|
||||
const note = targetRelation.note;
|
||||
|
||||
if (note) {
|
||||
note.invalidateSubtreeFlatText();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRelationDefinitions() {
|
||||
return this.getLabels()
|
||||
.filter(l => l.name.startsWith("relation:"));
|
||||
@@ -1054,28 +1068,28 @@ class BNote extends AbstractBeccaEntity {
|
||||
|
||||
/** @returns {BNote[]} */
|
||||
getAncestors() {
|
||||
if (!this.ancestorCache) {
|
||||
if (!this.__ancestorCache) {
|
||||
const noteIds = new Set();
|
||||
this.ancestorCache = [];
|
||||
this.__ancestorCache = [];
|
||||
|
||||
for (const parent of this.parents) {
|
||||
if (noteIds.has(parent.noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.ancestorCache.push(parent);
|
||||
this.__ancestorCache.push(parent);
|
||||
noteIds.add(parent.noteId);
|
||||
|
||||
for (const ancestorNote of parent.getAncestors()) {
|
||||
if (!noteIds.has(ancestorNote.noteId)) {
|
||||
this.ancestorCache.push(ancestorNote);
|
||||
this.__ancestorCache.push(ancestorNote);
|
||||
noteIds.add(ancestorNote.noteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.ancestorCache;
|
||||
return this.__ancestorCache;
|
||||
}
|
||||
|
||||
/** @returns {boolean} */
|
||||
@@ -1136,6 +1150,8 @@ class BNote extends AbstractBeccaEntity {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives all possible note paths leading to this note. Paths containing search note are ignored (could form cycles)
|
||||
*
|
||||
* @returns {string[][]} - array of notePaths (each represented by array of noteIds constituting the particular note path)
|
||||
*/
|
||||
getAllNotePaths() {
|
||||
@@ -1143,18 +1159,73 @@ class BNote extends AbstractBeccaEntity {
|
||||
return [['root']];
|
||||
}
|
||||
|
||||
const notePaths = [];
|
||||
const parentNotes = this.getParentNotes();
|
||||
let notePaths = [];
|
||||
|
||||
for (const parentNote of this.getParentNotes()) {
|
||||
for (const parentPath of parentNote.getAllNotePaths()) {
|
||||
parentPath.push(this.noteId);
|
||||
notePaths.push(parentPath);
|
||||
}
|
||||
if (parentNotes.length === 1) { // optimization for most common case
|
||||
notePaths = parentNotes[0].getAllNotePaths();
|
||||
} else {
|
||||
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
|
||||
}
|
||||
|
||||
for (const notePath of notePaths) {
|
||||
notePath.push(this.noteId);
|
||||
}
|
||||
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, notePath: Array<string>, isHidden: boolean}>}
|
||||
*/
|
||||
getSortedNotePathRecords(hoistedNoteId = 'root') {
|
||||
const isHoistedRoot = hoistedNoteId === 'root';
|
||||
|
||||
const notePaths = this.getAllNotePaths().map(path => ({
|
||||
notePath: path,
|
||||
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
||||
isArchived: path.some(noteId => this.becca.notes[noteId].isArchived),
|
||||
isHidden: path.includes('_hidden')
|
||||
}));
|
||||
|
||||
notePaths.sort((a, b) => {
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
return a.isArchived ? 1 : -1;
|
||||
} else if (a.isHidden !== b.isHidden) {
|
||||
return a.isHidden ? 1 : -1;
|
||||
} else {
|
||||
return a.notePath.length - b.notePath.length;
|
||||
}
|
||||
});
|
||||
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string[]} array of noteIds constituting the particular note path
|
||||
*/
|
||||
getBestNotePath(hoistedNoteId = 'root') {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId)[0]?.notePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string} serialized note path (e.g. 'root/a1h315/js725h')
|
||||
*/
|
||||
getBestNotePathString(hoistedNoteId = 'root') {
|
||||
const notePath = this.getBestNotePath(hoistedNoteId);
|
||||
|
||||
return notePath?.join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean - true if there's no non-hidden path, note is not cloned to the visible tree
|
||||
*/
|
||||
@@ -1168,9 +1239,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
return false;
|
||||
} else if (parentNote.noteId === '_hidden') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parentNote.isHiddenCompletely()) {
|
||||
} else if (!parentNote.isHiddenCompletely()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1364,7 +1433,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
|
||||
/**
|
||||
* @param parentNoteId
|
||||
* @returns {{success: boolean, message: string}}
|
||||
* @returns {{success: boolean, message: string, branchId: string, notePath: string}}
|
||||
*/
|
||||
cloneTo(parentNoteId) {
|
||||
const cloningService = require("../../services/cloning");
|
||||
@@ -1407,7 +1476,7 @@ class BNote extends AbstractBeccaEntity {
|
||||
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
|
||||
try {
|
||||
this.title = protectedSessionService.decryptString(this.title);
|
||||
this.flatTextCache = null;
|
||||
this.__flatTextCache = null;
|
||||
|
||||
this.isDecrypted = true;
|
||||
}
|
||||
|
||||
@@ -166,12 +166,14 @@ class BNoteRevision extends AbstractBeccaEntity {
|
||||
utcDateLastEdited: this.utcDateLastEdited,
|
||||
utcDateCreated: this.utcDateCreated,
|
||||
utcDateModified: this.utcDateModified,
|
||||
content: this.content, // used when retrieving full note revision to frontend
|
||||
contentLength: this.contentLength
|
||||
};
|
||||
}
|
||||
|
||||
getPojoToSave() {
|
||||
const pojo = this.getPojo();
|
||||
delete pojo.content; // not getting persisted
|
||||
delete pojo.contentLength; // not getting persisted
|
||||
|
||||
if (pojo.isProtected) {
|
||||
|
||||
@@ -16,6 +16,11 @@ class BOption extends AbstractBeccaEntity {
|
||||
constructor(row) {
|
||||
super();
|
||||
|
||||
this.updateFromRow(row);
|
||||
this.becca.options[this.name] = this;
|
||||
}
|
||||
|
||||
updateFromRow(row) {
|
||||
/** @type {string} */
|
||||
this.name = row.name;
|
||||
/** @type {string} */
|
||||
@@ -24,8 +29,6 @@ class BOption extends AbstractBeccaEntity {
|
||||
this.isSynced = !!row.isSynced;
|
||||
/** @type {string} */
|
||||
this.utcDateModified = row.utcDateModified;
|
||||
|
||||
this.becca.options[this.name] = this;
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
|
||||
@@ -2,7 +2,7 @@ const becca = require('./becca');
|
||||
const log = require('../services/log');
|
||||
const beccaService = require('./becca_service');
|
||||
const dateUtils = require('../services/date_utils');
|
||||
const { JSDOM } = require("jsdom");
|
||||
const {JSDOM} = require("jsdom");
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
@@ -168,7 +168,6 @@ function trimMime(mime) {
|
||||
}
|
||||
|
||||
mimeCache[mime] = str;
|
||||
mimeCache[mime] = str;
|
||||
}
|
||||
|
||||
return mimeCache[mime];
|
||||
@@ -224,8 +223,8 @@ function splitToWords(text) {
|
||||
*/
|
||||
function hasConnectingRelation(sourceNote, targetNote) {
|
||||
return sourceNote.getAttributes().find(attr => attr.type === 'relation'
|
||||
&& ['includenotelink', 'imagelink'].includes(attr.name)
|
||||
&& attr.value === targetNote.noteId);
|
||||
&& ['includenotelink', 'imagelink'].includes(attr.name)
|
||||
&& attr.value === targetNote.noteId);
|
||||
}
|
||||
|
||||
async function findSimilarNotes(noteId) {
|
||||
@@ -301,7 +300,7 @@ async function findSimilarNotes(noteId) {
|
||||
|
||||
for (const branch of parentNote.getParentBranches()) {
|
||||
score += gatherRewards(branch.prefix, 0.3)
|
||||
+ gatherAncestorRewards(branch.parentNote);
|
||||
+ gatherAncestorRewards(branch.parentNote);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +313,7 @@ async function findSimilarNotes(noteId) {
|
||||
|
||||
function computeScore(candidateNote) {
|
||||
let score = gatherRewards(trimMime(candidateNote.mime))
|
||||
+ gatherAncestorRewards(candidateNote);
|
||||
+ gatherAncestorRewards(candidateNote);
|
||||
|
||||
if (candidateNote.isDecrypted) {
|
||||
score += gatherRewards(candidateNote.title);
|
||||
@@ -382,7 +381,7 @@ async function findSimilarNotes(noteId) {
|
||||
score += 1;
|
||||
}
|
||||
else if (utcDateCreated.substr(0, 10) === dateLimits.minDate.substr(0, 10)
|
||||
|| utcDateCreated.substr(0, 10) === dateLimits.maxDate.substr(0, 10)) {
|
||||
|| utcDateCreated.substr(0, 10) === dateLimits.maxDate.substr(0, 10)) {
|
||||
if (displayRewards) {
|
||||
console.log("Adding reward for same day of creation");
|
||||
}
|
||||
@@ -405,7 +404,7 @@ async function findSimilarNotes(noteId) {
|
||||
let score = computeScore(candidateNote);
|
||||
|
||||
if (score >= 1.5) {
|
||||
const notePath = beccaService.getSomePath(candidateNote);
|
||||
const notePath = candidateNote.getBestNotePath();
|
||||
|
||||
// this takes care of note hoisting
|
||||
if (!notePath) {
|
||||
|
||||
@@ -17,7 +17,8 @@ function register(router) {
|
||||
'type': [v.mandatory, v.notNull, v.isAttributeType],
|
||||
'name': [v.mandatory, v.notNull, v.isString],
|
||||
'value': [v.notNull, v.isString],
|
||||
'isInheritable': [v.notNull, v.isBoolean]
|
||||
'isInheritable': [v.notNull, v.isBoolean],
|
||||
'position': [v.notNull, v.isInteger]
|
||||
};
|
||||
|
||||
eu.route(router, 'post' ,'/etapi/attributes', (req, res, next) => {
|
||||
@@ -39,18 +40,25 @@ function register(router) {
|
||||
}
|
||||
});
|
||||
|
||||
const ALLOWED_PROPERTIES_FOR_PATCH = {
|
||||
'value': [v.notNull, v.isString]
|
||||
const ALLOWED_PROPERTIES_FOR_PATCH_LABEL = {
|
||||
'value': [v.notNull, v.isString],
|
||||
'position': [v.notNull, v.isInteger]
|
||||
};
|
||||
|
||||
const ALLOWED_PROPERTIES_FOR_PATCH_RELATION = {
|
||||
'position': [v.notNull, v.isInteger]
|
||||
};
|
||||
|
||||
eu.route(router, 'patch' ,'/etapi/attributes/:attributeId', (req, res, next) => {
|
||||
const attribute = eu.getAndCheckAttribute(req.params.attributeId);
|
||||
|
||||
if (attribute.type === 'relation') {
|
||||
if (attribute.type === 'label') {
|
||||
eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH_LABEL);
|
||||
} else if (attribute.type === 'relation') {
|
||||
eu.getAndCheckNote(req.body.value);
|
||||
}
|
||||
|
||||
eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH);
|
||||
eu.validateAndPatch(attribute, req.body, ALLOWED_PROPERTIES_FOR_PATCH_RELATION);
|
||||
}
|
||||
|
||||
attribute.save();
|
||||
|
||||
|
||||
14
src/etapi/backup.js
Normal file
14
src/etapi/backup.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const eu = require("./etapi_utils");
|
||||
const backupService = require("../services/backup");
|
||||
|
||||
function register(router) {
|
||||
eu.route(router, 'put', '/etapi/backup/:backupName', async (req, res, next) => {
|
||||
await backupService.backupNow(req.params.backupName);
|
||||
|
||||
res.sendStatus(204);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
register
|
||||
};
|
||||
@@ -31,19 +31,13 @@ paths:
|
||||
'201':
|
||||
description: note created
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
properties:
|
||||
note:
|
||||
$ref: '#/components/schemas/Note'
|
||||
description: Created note
|
||||
branch:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
description: Created branch
|
||||
$ref: '#/components/schemas/NoteWithBranch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes:
|
||||
@@ -163,13 +157,13 @@ paths:
|
||||
'200':
|
||||
description: search response
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SearchResponse'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes/{noteId}:
|
||||
@@ -186,13 +180,13 @@ paths:
|
||||
'200':
|
||||
description: note response
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
patch:
|
||||
@@ -208,13 +202,13 @@ paths:
|
||||
'200':
|
||||
description: note updated
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
delete:
|
||||
@@ -226,7 +220,7 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes/{noteId}/content:
|
||||
@@ -288,7 +282,30 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes/{noteId}/import:
|
||||
parameters:
|
||||
- name: noteId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
post:
|
||||
description: Imports ZIP file into a given note.
|
||||
operationId: importZip
|
||||
responses:
|
||||
'201':
|
||||
description: note created
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/NoteWithBranch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes/{noteId}/note-revision:
|
||||
@@ -315,32 +332,10 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/branches/{branchId}:
|
||||
parameters:
|
||||
- name: branchId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
get:
|
||||
description: Returns a branch identified by its ID
|
||||
operationId: getBranchById
|
||||
responses:
|
||||
'200':
|
||||
description: branch response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/branches:
|
||||
post:
|
||||
description: >
|
||||
Create a branch (clone a note to a different location in the tree).
|
||||
@@ -357,23 +352,46 @@ paths:
|
||||
'200':
|
||||
description: branch updated (branch between parent note and child note already existed)
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
'201':
|
||||
description: branch created
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/branches/{branchId}:
|
||||
parameters:
|
||||
- name: branchId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
get:
|
||||
description: Returns a branch identified by its ID
|
||||
operationId: getBranchById
|
||||
responses:
|
||||
'200':
|
||||
description: branch response
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
patch:
|
||||
description: patch a branch identified by the branchId with changes in the body
|
||||
description: patch a branch identified by the branchId with changes in the body. Only prefix and notePosition can be updated. If you want to update other properties, you need to delete the old branch and create a new one.
|
||||
operationId: patchBranchById
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -385,13 +403,13 @@ paths:
|
||||
'200':
|
||||
description: branch updated
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
delete:
|
||||
@@ -405,7 +423,30 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/attributes:
|
||||
post:
|
||||
description: create an attribute for a given note
|
||||
operationId: postAttribute
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
responses:
|
||||
'201':
|
||||
description: attribute created
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/attributes/{attributeId}:
|
||||
@@ -422,39 +463,17 @@ paths:
|
||||
'200':
|
||||
description: attribute response
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
post:
|
||||
description: create an attribute for a given note
|
||||
operationId: postAttribute
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
responses:
|
||||
'201':
|
||||
description: attribute created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
patch:
|
||||
description: patch a attribute identified by the attributeId with changes in the body
|
||||
description: patch a attribute identified by the attributeId with changes in the body. For labels, only value and position can be updated. For relations, only position can be updated. If you want to modify other properties, you need to delete the old attribute and create a new one.
|
||||
operationId: patchAttributeById
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -466,13 +485,13 @@ paths:
|
||||
'200':
|
||||
description: attribute updated
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Attribute'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
delete:
|
||||
@@ -484,7 +503,7 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/refresh-note-ordering/{parentNoteId}:
|
||||
@@ -506,7 +525,7 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/inbox/{date}:
|
||||
@@ -527,13 +546,13 @@ paths:
|
||||
'200':
|
||||
description: inbox note
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/calendar/days/{date}:
|
||||
@@ -552,13 +571,13 @@ paths:
|
||||
'200':
|
||||
description: day note
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/calendar/weeks/{date}:
|
||||
@@ -577,13 +596,13 @@ paths:
|
||||
'200':
|
||||
description: week note
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/calendar/months/{month}:
|
||||
@@ -602,13 +621,13 @@ paths:
|
||||
'200':
|
||||
description: month note
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/calendar/years/{year}:
|
||||
@@ -627,13 +646,13 @@ paths:
|
||||
'200':
|
||||
description: year note
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Note'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/auth/login:
|
||||
@@ -654,7 +673,7 @@ paths:
|
||||
'201':
|
||||
description: auth token
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
properties:
|
||||
authToken:
|
||||
@@ -665,7 +684,7 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/auth/logout:
|
||||
@@ -678,7 +697,7 @@ paths:
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/app-info:
|
||||
@@ -689,16 +708,35 @@ paths:
|
||||
'200':
|
||||
description: app info
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AppInfo'
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/backup/{backupName}:
|
||||
parameters:
|
||||
- name: backupName
|
||||
in: path
|
||||
required: true
|
||||
description: If the backupName is e.g. "now", then the backup will be written to "backup-now.db" file
|
||||
schema:
|
||||
$ref: '#/components/schemas/StringId'
|
||||
put:
|
||||
description: Create a database backup under a given name
|
||||
operationId: createBackup
|
||||
responses:
|
||||
'204':
|
||||
description: backup has been created
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json; charset=utf-8:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
EtapiTokenAuth:
|
||||
@@ -774,7 +812,7 @@ components:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum: [text, code, render, file, image, search, relationMap, book, noteMap, mermaid, webView, shortcut]
|
||||
enum: [text, code, render, file, image, search, relationMap, book, noteMap, mermaid, webView, shortcut, doc, contentWidget, launcher]
|
||||
mime:
|
||||
type: string
|
||||
isProtected:
|
||||
@@ -810,9 +848,6 @@ components:
|
||||
Branch:
|
||||
type: object
|
||||
description: Branch places the note into the tree, it represents the relationship between a parent note and child note
|
||||
required:
|
||||
- noteId
|
||||
- parentNoteId
|
||||
properties:
|
||||
branchId:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
@@ -834,11 +869,16 @@ components:
|
||||
utcDateModified:
|
||||
$ref: '#/components/schemas/UtcDateTime'
|
||||
readOnly: true
|
||||
NoteWithBranch:
|
||||
type: object
|
||||
properties:
|
||||
note:
|
||||
$ref: '#/components/schemas/Note'
|
||||
branch:
|
||||
$ref: '#/components/schemas/Branch'
|
||||
Attribute:
|
||||
type: object
|
||||
description: Attribute (Label, Relation) is a key-value record attached to a note.
|
||||
required:
|
||||
- noteId
|
||||
properties:
|
||||
attributeId:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
@@ -851,7 +891,7 @@ components:
|
||||
enum: [label, relation]
|
||||
name:
|
||||
type: string
|
||||
pattern: '^[\p{L}\p{N}_:]+'
|
||||
pattern: '^[^\s]+'
|
||||
example: shareCss
|
||||
value:
|
||||
type: string
|
||||
@@ -881,15 +921,19 @@ components:
|
||||
description: debugging info on parsing the search query enabled with &debug=true parameter
|
||||
EntityId:
|
||||
type: string
|
||||
pattern: '[a-zA-Z0-9]{4,32}'
|
||||
pattern: '[a-zA-Z0-9_]{4,32}'
|
||||
example: evnnmvHTCgIn
|
||||
StringId:
|
||||
type: string
|
||||
pattern: '[a-zA-Z0-9_]{1,32}'
|
||||
example: my_ID
|
||||
EntityIdList:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
LocalDateTime:
|
||||
type: string
|
||||
pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+[0-9]{4}'
|
||||
pattern: '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[\+\-][0-9]{4}'
|
||||
example: 2021-12-31 20:18:11.939+0100
|
||||
UtcDateTime:
|
||||
type: string
|
||||
@@ -897,10 +941,6 @@ components:
|
||||
example: 2021-12-31 19:18:11.939Z
|
||||
AppInfo:
|
||||
type: object
|
||||
required:
|
||||
- statu
|
||||
- code
|
||||
- message
|
||||
properties:
|
||||
appVersion:
|
||||
type: string
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** @param {BNote} note */
|
||||
function mapNoteToPojo(note) {
|
||||
return {
|
||||
noteId: note.noteId,
|
||||
@@ -17,6 +18,7 @@ function mapNoteToPojo(note) {
|
||||
};
|
||||
}
|
||||
|
||||
/** @param {BBranch} branch */
|
||||
function mapBranchToPojo(branch) {
|
||||
return {
|
||||
branchId: branch.branchId,
|
||||
@@ -29,6 +31,7 @@ function mapBranchToPojo(branch) {
|
||||
};
|
||||
}
|
||||
|
||||
/** @param {BAttribute} attr */
|
||||
function mapAttributeToPojo(attr) {
|
||||
return {
|
||||
attributeId: attr.attributeId,
|
||||
@@ -46,4 +49,4 @@ module.exports = {
|
||||
mapNoteToPojo,
|
||||
mapBranchToPojo,
|
||||
mapAttributeToPojo
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ const v = require("./validators");
|
||||
const searchService = require("../services/search/services/search");
|
||||
const SearchContext = require("../services/search/search_context");
|
||||
const zipExportService = require("../services/export/zip");
|
||||
const zipImportService = require("../services/import/zip");
|
||||
|
||||
function register(router) {
|
||||
eu.route(router, 'get', '/etapi/notes', (req, res, next) => {
|
||||
@@ -141,11 +142,21 @@ function register(router) {
|
||||
// (e.g. branchIds are not seen in UI), that we export "note export" instead.
|
||||
const branch = note.getParentBranches()[0];
|
||||
|
||||
console.log(note.getParentBranches());
|
||||
|
||||
zipExportService.exportToZip(taskContext, branch, format, res);
|
||||
});
|
||||
|
||||
eu.route(router, 'post' ,'/etapi/notes/:noteId/import', (req, res, next) => {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
const taskContext = new TaskContext('no-progress-reporting');
|
||||
|
||||
zipImportService.importZip(taskContext, req.body, note).then(importedNote => {
|
||||
res.status(201).json({
|
||||
note: mappers.mapNoteToPojo(importedNote),
|
||||
branch: mappers.mapBranchToPojo(importedNote.getBranches()[0]),
|
||||
});
|
||||
}); // we need better error handling here, async errors won't be properly processed.
|
||||
});
|
||||
|
||||
eu.route(router, 'post' ,'/etapi/notes/:noteId/note-revision', (req, res, next) => {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ function register(router) {
|
||||
const {date} = req.params;
|
||||
|
||||
if (!isValidDate(date)) {
|
||||
throw getDateInvalidError(res, date);
|
||||
throw getDateInvalidError(date);
|
||||
}
|
||||
|
||||
const note = specialNotesService.getInboxNote(date);
|
||||
@@ -31,7 +31,7 @@ function register(router) {
|
||||
const {date} = req.params;
|
||||
|
||||
if (!isValidDate(date)) {
|
||||
throw getDateInvalidError(res, date);
|
||||
throw getDateInvalidError(date);
|
||||
}
|
||||
|
||||
const note = dateNotesService.getDayNote(date);
|
||||
@@ -42,7 +42,7 @@ function register(router) {
|
||||
const {date} = req.params;
|
||||
|
||||
if (!isValidDate(date)) {
|
||||
throw getDateInvalidError(res, date);
|
||||
throw getDateInvalidError(date);
|
||||
}
|
||||
|
||||
const note = dateNotesService.getWeekNote(date);
|
||||
@@ -53,7 +53,7 @@ function register(router) {
|
||||
const {month} = req.params;
|
||||
|
||||
if (!/[0-9]{4}-[0-9]{2}/.test(month)) {
|
||||
throw getMonthInvalidError(res, month);
|
||||
throw getMonthInvalidError(month);
|
||||
}
|
||||
|
||||
const note = dateNotesService.getMonthNote(month);
|
||||
@@ -64,7 +64,7 @@ function register(router) {
|
||||
const {year} = req.params;
|
||||
|
||||
if (!/[0-9]{4}/.test(year)) {
|
||||
throw getYearInvalidError(res, year);
|
||||
throw getYearInvalidError(year);
|
||||
}
|
||||
|
||||
const note = dateNotesService.getYearNote(year);
|
||||
|
||||
@@ -173,7 +173,7 @@ export default class Entrypoints extends Component {
|
||||
const resp = await server.post(`sql/execute/${note.noteId}`);
|
||||
|
||||
if (!resp.success) {
|
||||
toastService.showError(`Error occurred while executing SQL query: ${resp.message}`);
|
||||
toastService.showError(`Error occurred while executing SQL query: ${resp.error}`);
|
||||
}
|
||||
|
||||
await appContext.triggerEvent('sqlQueryResults', {ntxId: ntxId, results: resp.results});
|
||||
|
||||
@@ -176,9 +176,12 @@ class NoteContext extends Component {
|
||||
}
|
||||
|
||||
getTabState() {
|
||||
if (!this.notePath && this.hoistedNoteId === 'root') {
|
||||
if (this.hoistedNoteId !== 'root') {
|
||||
// keeping empty hoisted tab is esp. important for mobile (e.g. opened launcher config)
|
||||
return null;
|
||||
|
||||
if (!this.notePath && this.getSubContexts().length === 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -226,6 +229,10 @@ class NoteContext extends Component {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.viewScope.viewMode === 'source') {
|
||||
return true;
|
||||
}
|
||||
|
||||
const noteComplement = await this.getNoteComplement();
|
||||
|
||||
const sizeLimit = this.note.type === 'text'
|
||||
|
||||
@@ -55,6 +55,13 @@ export default class RootCommandExecutor extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
openNoteCustomCommand() {
|
||||
const noteId = appContext.tabManager.getActiveContextNoteId();
|
||||
if (noteId) {
|
||||
openService.openNoteCustom(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
enterProtectedSessionCommand() {
|
||||
protectedSessionService.enterProtectedSession();
|
||||
}
|
||||
|
||||
@@ -388,7 +388,12 @@ export default class TabManager extends Component {
|
||||
await this.triggerEvent('beforeNoteContextRemove', { ntxIds: ntxIdsToRemove });
|
||||
|
||||
if (!noteContextToRemove.isMainContext()) {
|
||||
await this.activateNoteContext(noteContextToRemove.getMainContext().ntxId);
|
||||
const siblings = noteContextToRemove.getMainContext().getSubContexts();
|
||||
const idx = siblings.findIndex(nc => nc.ntxId === noteContextToRemove.ntxId);
|
||||
const contextToActivateIdx = idx === siblings.length - 1 ? idx - 1 : idx + 1;
|
||||
const contextToActivate = siblings[contextToActivateIdx];
|
||||
|
||||
await this.activateNoteContext(contextToActivate.ntxId);
|
||||
}
|
||||
else if (this.mainNoteContexts.length <= 1) {
|
||||
await this.openAndActivateEmptyTab();
|
||||
@@ -446,16 +451,23 @@ export default class TabManager extends Component {
|
||||
this.tabsUpdate.scheduleUpdate();
|
||||
}
|
||||
|
||||
noteContextReorderEvent({ntxIdsInOrder}) {
|
||||
const order = {};
|
||||
let i = 0;
|
||||
|
||||
for (const ntxId of ntxIdsInOrder) {
|
||||
order[ntxId] = i++;
|
||||
}
|
||||
noteContextReorderEvent({ntxIdsInOrder, oldMainNtxId, newMainNtxId}) {
|
||||
const order = Object.fromEntries(ntxIdsInOrder.map((v, i) => [v, i]));
|
||||
|
||||
this.children.sort((a, b) => order[a.ntxId] < order[b.ntxId] ? -1 : 1);
|
||||
|
||||
if (oldMainNtxId && newMainNtxId) {
|
||||
this.children.forEach(c => {
|
||||
if (c.ntxId === newMainNtxId) {
|
||||
// new main context has null mainNtxId
|
||||
c.mainNtxId = null;
|
||||
} else if (c.ntxId === oldMainNtxId || c.mainNtxId === oldMainNtxId) {
|
||||
// old main context or subcontexts all have the new mainNtxId
|
||||
c.mainNtxId = newMainNtxId;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.tabsUpdate.scheduleUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import contextMenu from "./menus/context_menu.js";
|
||||
import DesktopLayout from "./layouts/desktop_layout.js";
|
||||
import glob from "./services/glob.js";
|
||||
import zoomService from './components/zoom.js';
|
||||
import options from "./services/options.js";
|
||||
|
||||
bundleService.getWidgetBundlesByParent().then(widgetBundles => {
|
||||
appContext.setLayout(new DesktopLayout(widgetBundles));
|
||||
@@ -115,11 +116,27 @@ if (utils.isElectron()) {
|
||||
? (`${params.selectionText.substr(0, 13)}…`)
|
||||
: params.selectionText;
|
||||
|
||||
// Read the search engine from the options and fallback to DuckDuckGo if the option is not set.
|
||||
const customSearchEngineName = options.get("customSearchEngineName");
|
||||
const customSearchEngineUrl = options.get("customSearchEngineUrl");
|
||||
let searchEngineName;
|
||||
let searchEngineUrl;
|
||||
if (customSearchEngineName && customSearchEngineUrl) {
|
||||
searchEngineName = customSearchEngineName;
|
||||
searchEngineUrl = customSearchEngineUrl;
|
||||
} else {
|
||||
searchEngineName = "Duckduckgo";
|
||||
searchEngineUrl = "https://duckduckgo.com/?q={keyword}";
|
||||
}
|
||||
|
||||
// Replace the placeholder with the real search keyword.
|
||||
let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText));
|
||||
|
||||
items.push({
|
||||
enabled: editFlags.canPaste,
|
||||
title: `Search for "${shortenedSelection}" with DuckDuckGo`,
|
||||
title: `Search for "${shortenedSelection}" with ${searchEngineName}`,
|
||||
uiIcon: "bx bx-search-alt",
|
||||
handler: () => electron.shell.openExternal(`https://duckduckgo.com/?q=${encodeURIComponent(params.selectionText)}`)
|
||||
handler: () => electron.shell.openExternal(searchUrl)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
<p>Keyboard launcher for this launcher action can be configured in Options -> Launchers.</p>
|
||||
<p>Keyboard shortcut for this launcher action can be configured in Options -> Shortcuts.</p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<ol>
|
||||
<li><code>target</code> - note which should be opened upon activating the launcher</li>
|
||||
<li><code>hoistedNote</code> - optional, will change the hoisted note before opening the target note</li>
|
||||
<li><code>keyboardLauncher</code> - optional, pressing the keyboard launcher will open the note</li>
|
||||
<li><code>keyboardShortcut</code> - optional, pressing the keyboard shortcut will open the note</li>
|
||||
</ol>
|
||||
|
||||
<p>Launchbar displays the title / icon from the launcher which does not necessarily mirrors those of the target note.</p>
|
||||
<p>Launchbar displays the title / icon from the launcher which does not necessarily mirror those of the target note.</p>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<ol>
|
||||
<li><code>script</code> - relation to the script note which should be executed upon launcher activation</li>
|
||||
<li><code>keyboardLauncher</code> - optional, pressing the keyboard launcher will activate the launcher</li>
|
||||
<li><code>keyboardShortcut</code> - optional, pressing the keyboard shortcut will activate the launcher</li>
|
||||
</ol>
|
||||
|
||||
<h4>Example script</h4>
|
||||
|
||||
@@ -73,7 +73,7 @@ class FNote {
|
||||
this.mime = row.mime;
|
||||
}
|
||||
|
||||
addParent(parentNoteId, branchId) {
|
||||
addParent(parentNoteId, branchId, sort = true) {
|
||||
if (parentNoteId === 'none') {
|
||||
return;
|
||||
}
|
||||
@@ -83,6 +83,10 @@ class FNote {
|
||||
}
|
||||
|
||||
this.parentToBranch[parentNoteId] = branchId;
|
||||
|
||||
if (sort) {
|
||||
this.sortParents();
|
||||
}
|
||||
}
|
||||
|
||||
addChild(childNoteId, branchId, sort = true) {
|
||||
@@ -189,7 +193,7 @@ class FNote {
|
||||
|
||||
// will sort the parents so that non-search & non-archived are first and archived at the end
|
||||
// this is done so that non-search & non-archived paths are always explored as first when looking for note path
|
||||
resortParents() {
|
||||
sortParents() {
|
||||
this.parents.sort((aNoteId, bNoteId) => {
|
||||
const aBranchId = this.parentToBranch[aNoteId];
|
||||
|
||||
@@ -197,7 +201,7 @@ class FNote {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const aNote = this.froca.getNoteFromCache([aNoteId]);
|
||||
const aNote = this.froca.getNoteFromCache(aNoteId);
|
||||
|
||||
if (aNote.isArchived || aNote.isHiddenCompletely()) {
|
||||
return 1;
|
||||
@@ -243,6 +247,11 @@ class FNote {
|
||||
return this.__filterAttrs(this.__getCachedAttributes([]), type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} path
|
||||
* @return {FAttribute[]}
|
||||
* @private
|
||||
*/
|
||||
__getCachedAttributes(path) {
|
||||
// notes/clones cannot form tree cycles, it is possible to create attribute inheritance cycle via templates
|
||||
// when template instance is a parent of template itself
|
||||
@@ -295,63 +304,49 @@ class FNote {
|
||||
return this.noteId === 'root';
|
||||
}
|
||||
|
||||
getAllNotePaths(encounteredNoteIds = null) {
|
||||
/**
|
||||
* Gives all possible note paths leading to this note. Paths containing search note are ignored (could form cycles)
|
||||
*
|
||||
* @returns {string[][]} - array of notePaths (each represented by array of noteIds constituting the particular note path)
|
||||
*/
|
||||
getAllNotePaths() {
|
||||
if (this.noteId === 'root') {
|
||||
return [['root']];
|
||||
}
|
||||
|
||||
if (!encounteredNoteIds) {
|
||||
encounteredNoteIds = new Set();
|
||||
const parentNotes = this.getParentNotes().filter(note => note.type !== 'search');
|
||||
let notePaths = [];
|
||||
|
||||
if (parentNotes.length === 1) { // optimization for most common case
|
||||
notePaths = parentNotes[0].getAllNotePaths();
|
||||
} else {
|
||||
notePaths = parentNotes.flatMap(parentNote => parentNote.getAllNotePaths());
|
||||
}
|
||||
|
||||
encounteredNoteIds.add(this.noteId);
|
||||
|
||||
const parentNotes = this.getParentNotes();
|
||||
let paths;
|
||||
|
||||
if (parentNotes.length === 1) { // optimization for the most common case
|
||||
if (encounteredNoteIds.has(parentNotes[0].noteId)) {
|
||||
return [];
|
||||
}
|
||||
else {
|
||||
paths = parentNotes[0].getAllNotePaths(encounteredNoteIds);
|
||||
}
|
||||
}
|
||||
else {
|
||||
paths = [];
|
||||
|
||||
for (const parentNote of parentNotes) {
|
||||
if (encounteredNoteIds.has(parentNote.noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newSet = new Set(encounteredNoteIds);
|
||||
|
||||
paths.push(...parentNote.getAllNotePaths(newSet));
|
||||
}
|
||||
for (const notePath of notePaths) {
|
||||
notePath.push(this.noteId);
|
||||
}
|
||||
|
||||
for (const path of paths) {
|
||||
path.push(this.noteId);
|
||||
}
|
||||
|
||||
return paths;
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
getSortedNotePaths(hoistedNotePath = 'root') {
|
||||
/**
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {Array<{isArchived: boolean, isInHoistedSubTree: boolean, notePath: Array<string>, isHidden: boolean}>}
|
||||
*/
|
||||
getSortedNotePathRecords(hoistedNoteId = 'root') {
|
||||
const isHoistedRoot = hoistedNoteId === 'root';
|
||||
|
||||
const notePaths = this.getAllNotePaths().map(path => ({
|
||||
notePath: path,
|
||||
isInHoistedSubTree: path.includes(hoistedNotePath),
|
||||
isArchived: path.find(noteId => froca.notes[noteId].isArchived),
|
||||
isSearch: path.find(noteId => froca.notes[noteId].type === 'search'),
|
||||
isInHoistedSubTree: isHoistedRoot || path.includes(hoistedNoteId),
|
||||
isArchived: path.some(noteId => froca.notes[noteId].isArchived),
|
||||
isHidden: path.includes('_hidden')
|
||||
}));
|
||||
|
||||
notePaths.sort((a, b) => {
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isSearch !== b.isSearch) {
|
||||
return a.isSearch ? 1 : -1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
return a.isArchived ? 1 : -1;
|
||||
} else if (a.isHidden !== b.isHidden) {
|
||||
@@ -364,6 +359,28 @@ class FNote {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string[]} array of noteIds constituting the particular note path
|
||||
*/
|
||||
getBestNotePath(hoistedNoteId = 'root') {
|
||||
return this.getSortedNotePathRecords(hoistedNoteId)[0]?.notePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns note path considered to be the "best"
|
||||
*
|
||||
* @param {string} [hoistedNoteId='root']
|
||||
* @return {string} serialized note path (e.g. 'root/a1h315/js725h')
|
||||
*/
|
||||
getBestNotePathString(hoistedNoteId = 'root') {
|
||||
const notePath = this.getBestNotePath(hoistedNoteId);
|
||||
|
||||
return notePath?.join("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean - true if there's no non-hidden path, note is not cloned to the visible tree
|
||||
*/
|
||||
@@ -375,7 +392,7 @@ class FNote {
|
||||
for (const parentNote of this.getParentNotes()) {
|
||||
if (parentNote.noteId === 'root') {
|
||||
return false;
|
||||
} else if (parentNote.noteId === '_hidden') {
|
||||
} else if (parentNote.noteId === '_hidden' || parentNote.type === 'search') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -387,6 +404,13 @@ class FNote {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FAttribute[]} attributes
|
||||
* @param {string} type
|
||||
* @param {string} name
|
||||
* @return {FAttribute[]}
|
||||
* @private
|
||||
*/
|
||||
__filterAttrs(attributes, type, name) {
|
||||
this.__validateTypeName(type, name);
|
||||
|
||||
@@ -523,7 +547,9 @@ class FNote {
|
||||
* @returns {boolean} true if note has an attribute with given type and name (including inherited)
|
||||
*/
|
||||
hasAttribute(type, name) {
|
||||
return !!this.getAttribute(type, name);
|
||||
const attributes = this.getAttributes();
|
||||
|
||||
return attributes.some(attr => attr.name === name && attr.type === type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -591,6 +617,20 @@ class FNote {
|
||||
*/
|
||||
hasLabel(name) { return this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {boolean} true if label exists (including inherited) and does not have "false" value.
|
||||
*/
|
||||
isLabelTruthy(name) {
|
||||
const label = this.getLabel(name);
|
||||
|
||||
if (!label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return label && label.value !== 'false';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {boolean} true if relation exists (excluding inherited)
|
||||
@@ -702,7 +742,14 @@ class FNote {
|
||||
});
|
||||
|
||||
// attrs are not resorted if position changes after initial load
|
||||
promotedAttrs.sort((a, b) => a.position < b.position ? -1 : 1);
|
||||
promotedAttrs.sort((a, b) => {
|
||||
if (a.noteId === b.noteId) {
|
||||
return a.position < b.position ? -1 : 1;
|
||||
} else {
|
||||
// inherited promoted attributes should stay grouped: https://github.com/zadam/trilium/issues/3761
|
||||
return a.noteId < b.noteId ? -1 : 1;
|
||||
}
|
||||
});
|
||||
|
||||
return promotedAttrs;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ import CodeButtonsWidget from "../widgets/floating_buttons/code_buttons.js";
|
||||
import ApiLogWidget from "../widgets/api_log.js";
|
||||
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
|
||||
import ScriptExecutorWidget from "../widgets/ribbon_widgets/script_executor.js";
|
||||
import MovePaneButton from "../widgets/buttons/move_pane_button.js";
|
||||
|
||||
export default class DesktopLayout {
|
||||
constructor(customWidgets) {
|
||||
@@ -123,11 +124,17 @@ export default class DesktopLayout {
|
||||
.child(new NoteIconWidget())
|
||||
.child(new NoteTitleWidget())
|
||||
.child(new SpacerWidget(0, 1))
|
||||
.child(new MovePaneButton(true))
|
||||
.child(new MovePaneButton(false))
|
||||
.child(new ClosePaneButton())
|
||||
.child(new CreatePaneButton())
|
||||
)
|
||||
.child(
|
||||
new RibbonContainer()
|
||||
// order of the widgets matter. Some of these want to "activate" themselves
|
||||
// when visible, when this happens to multiple of them, the first one "wins".
|
||||
// promoted attributes should always win.
|
||||
.ribbon(new PromotedAttributesWidget())
|
||||
.ribbon(new ScriptExecutorWidget())
|
||||
.ribbon(new SearchDefinitionWidget())
|
||||
.ribbon(new EditedNotesWidget())
|
||||
@@ -135,7 +142,6 @@ export default class DesktopLayout {
|
||||
.ribbon(new NotePropertiesWidget())
|
||||
.ribbon(new FilePropertiesWidget())
|
||||
.ribbon(new ImagePropertiesWidget())
|
||||
.ribbon(new PromotedAttributesWidget())
|
||||
.ribbon(new BasicPropertiesWidget())
|
||||
.ribbon(new OwnedAttributeListWidget())
|
||||
.ribbon(new InheritedAttributesWidget())
|
||||
|
||||
@@ -99,11 +99,16 @@ class ContextMenu {
|
||||
const $item = $("<li>")
|
||||
.addClass("dropdown-item")
|
||||
.append($link)
|
||||
.on('contextmenu', e => false)
|
||||
// important to use mousedown instead of click since the former does not change focus
|
||||
// (especially important for focused text for spell check)
|
||||
.on('mousedown', e => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (e.which !== 1) { // only left click triggers menu items
|
||||
return false;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
|
||||
if (item.handler) {
|
||||
@@ -142,7 +147,9 @@ class ContextMenu {
|
||||
// "contextmenu" event also triggers "click" event which depending on the timing can close just opened context menu
|
||||
// we might filter out right clicks, but then it's better if even right clicks close the context menu
|
||||
if (Date.now() - this.dateContextMenuOpenedMs > 300) {
|
||||
this.$widget.hide();
|
||||
// seems like if we hide the menu immediately, some clicks can get propagated to the underlying component
|
||||
// see https://github.com/zadam/trilium/pull/3805 for details
|
||||
setTimeout(() => this.$widget.hide(), 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ async function moveBeforeBranch(branchIdsToMove, beforeBranchId) {
|
||||
branchIdsToMove = filterRootNote(branchIdsToMove);
|
||||
branchIdsToMove = filterSearchBranches(branchIdsToMove);
|
||||
|
||||
const beforeBranch = await froca.getBranch(beforeBranchId);
|
||||
const beforeBranch = froca.getBranch(beforeBranchId);
|
||||
|
||||
if (['root', '_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(beforeBranch.noteId)) {
|
||||
toastService.showError('Cannot move notes here.');
|
||||
@@ -31,7 +31,7 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) {
|
||||
branchIdsToMove = filterRootNote(branchIdsToMove);
|
||||
branchIdsToMove = filterSearchBranches(branchIdsToMove);
|
||||
|
||||
const afterNote = await froca.getBranch(afterBranchId).getNote();
|
||||
const afterNote = froca.getBranch(afterBranchId).getNote();
|
||||
|
||||
const forbiddenNoteIds = [
|
||||
'root',
|
||||
@@ -59,7 +59,7 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) {
|
||||
}
|
||||
|
||||
async function moveToParentNote(branchIdsToMove, newParentBranchId) {
|
||||
const newParentBranch = await froca.getBranch(newParentBranchId);
|
||||
const newParentBranch = froca.getBranch(newParentBranchId);
|
||||
|
||||
if (newParentBranch.noteId === '_lbRoot') {
|
||||
toastService.showError('Cannot move notes here.');
|
||||
@@ -165,7 +165,7 @@ function filterRootNote(branchIds) {
|
||||
const hoistedNoteId = hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
return branchIds.filter(branchId => {
|
||||
const branch = froca.getBranch(branchId);
|
||||
const branch = froca.getBranch(branchId);
|
||||
|
||||
return branch.noteId !== 'root'
|
||||
&& branch.noteId !== hoistedNoteId;
|
||||
@@ -227,7 +227,7 @@ async function cloneNoteToBranch(childNoteId, parentBranchId, prefix) {
|
||||
}
|
||||
}
|
||||
|
||||
async function cloneNoteToNote(childNoteId, parentNoteId, prefix) {
|
||||
async function cloneNoteToParentNote(childNoteId, parentNoteId, prefix) {
|
||||
const resp = await server.put(`notes/${childNoteId}/clone-to-note/${parentNoteId}`, {
|
||||
prefix: prefix
|
||||
});
|
||||
@@ -254,5 +254,5 @@ export default {
|
||||
moveNodeUpInHierarchy,
|
||||
cloneNoteAfter,
|
||||
cloneNoteToBranch,
|
||||
cloneNoteToNote,
|
||||
cloneNoteToParentNote,
|
||||
};
|
||||
|
||||
@@ -14,7 +14,8 @@ function createClassForColor(color) {
|
||||
const className = `color-${normalizedColorName}`;
|
||||
|
||||
if (!registeredClasses.has(className)) {
|
||||
$("head").append(`<style>.${className} { color: ${color} !important; }</style>`);
|
||||
// make the active fancytree selector more specific than the normal color setting
|
||||
$("head").append(`<style>.${className}, span.fancytree-active.${className} { color: ${color} !important; }</style>`);
|
||||
|
||||
registeredClasses.add(className);
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ class Froca {
|
||||
const childNote = this.notes[branch.noteId];
|
||||
|
||||
if (childNote) {
|
||||
childNote.addParent(branch.parentNoteId, branch.branchId);
|
||||
childNote.addParent(branch.parentNoteId, branch.branchId, false);
|
||||
}
|
||||
|
||||
const parentNote = this.notes[branch.parentNoteId];
|
||||
@@ -152,6 +152,7 @@ class Froca {
|
||||
// sort all of them at once, this avoids repeated sorts (#1480)
|
||||
for (const noteId of noteIdsToSort) {
|
||||
this.notes[noteId].sortChildren();
|
||||
this.notes[noteId].sortParents();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ async function processEntityChanges(entityChanges) {
|
||||
if (ec.entityName === 'notes') {
|
||||
processNoteChange(loadResults, ec);
|
||||
} else if (ec.entityName === 'branches') {
|
||||
processBranchChange(loadResults, ec);
|
||||
await processBranchChange(loadResults, ec);
|
||||
} else if (ec.entityName === 'attributes') {
|
||||
processAttributeChange(loadResults, ec);
|
||||
} else if (ec.entityName === 'note_reordering') {
|
||||
@@ -105,7 +105,7 @@ function processNoteChange(loadResults, ec) {
|
||||
}
|
||||
}
|
||||
|
||||
function processBranchChange(loadResults, ec) {
|
||||
async function processBranchChange(loadResults, ec) {
|
||||
if (ec.isErased && ec.entityId in froca.branches) {
|
||||
utils.reloadFrontendApp(`${ec.entityName} ${ec.entityId} is erased, need to do complete reload.`);
|
||||
return;
|
||||
@@ -139,7 +139,15 @@ function processBranchChange(loadResults, ec) {
|
||||
loadResults.addBranch(ec.entityId, ec.componentId);
|
||||
|
||||
const childNote = froca.notes[ec.entity.noteId];
|
||||
const parentNote = froca.notes[ec.entity.parentNoteId];
|
||||
let parentNote = froca.notes[ec.entity.parentNoteId];
|
||||
|
||||
if (childNote && !childNote.isRoot() && !parentNote) {
|
||||
// a branch cannot exist without the parent
|
||||
// a note loaded into froca has to also contain all its ancestors
|
||||
// this problem happened e.g. in sharing where _share was hidden and thus not loaded
|
||||
// sharing meant cloning into _share, which crashed because _share was not loaded
|
||||
parentNote = await froca.getNote(ec.entity.parentNoteId);
|
||||
}
|
||||
|
||||
if (branch) {
|
||||
branch.update(ec.entity);
|
||||
|
||||
@@ -65,7 +65,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
await ws.waitForMaxKnownEntityChangeId();
|
||||
|
||||
await appContext.tabManager.getActiveContext().setNote(notePath);
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -82,7 +82,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
await appContext.tabManager.openContextWithNote(notePath, { activate });
|
||||
|
||||
if (activate) {
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -100,10 +100,10 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
|
||||
const {ntxId} = subContexts[subContexts.length - 1];
|
||||
|
||||
appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
||||
await appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath});
|
||||
|
||||
if (activate) {
|
||||
appContext.triggerEvent('focusAndSelectTitle');
|
||||
await appContext.triggerEvent('focusAndSelectTitle');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -483,6 +483,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
*/
|
||||
this.randomString = utils.randomString;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @param {int} size in bytes
|
||||
* @return {string} formatted string
|
||||
*/
|
||||
this.formatNoteSize = utils.formatNoteSize;
|
||||
|
||||
this.logMessages = {};
|
||||
this.logSpacedUpdates = {};
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ export async function uploadFiles(parentNoteId, files, options) {
|
||||
}
|
||||
|
||||
const taskId = utils.randomString(10);
|
||||
let noteId;
|
||||
let counter = 0;
|
||||
|
||||
for (const file of files) {
|
||||
@@ -25,19 +24,19 @@ export async function uploadFiles(parentNoteId, files, options) {
|
||||
formData.append(key, options[key]);
|
||||
}
|
||||
|
||||
({noteId} = await $.ajax({
|
||||
await $.ajax({
|
||||
url: `${baseApiUrl}notes/${parentNoteId}/import`,
|
||||
headers: await server.getHeaders(),
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
type: 'POST',
|
||||
timeout: 60 * 60 * 1000,
|
||||
error: function(xhr) {
|
||||
error: function (xhr) {
|
||||
toastService.showError(`Import failed: ${xhr.responseText}`);
|
||||
},
|
||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
||||
processData: false, // NEEDED, DON'T REMOVE THIS
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,4 +73,4 @@ ws.subscribeToMessages(async message => {
|
||||
|
||||
export default {
|
||||
uploadFiles
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,11 +105,14 @@ function goToLink(evt) {
|
||||
|
||||
const ctrlKey = utils.isCtrlKey(evt);
|
||||
|
||||
const leftClick = evt.which === 1;
|
||||
const middleClick = evt.which === 2;
|
||||
|
||||
if (notePath) {
|
||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
||||
if ((leftClick && ctrlKey) || middleClick) {
|
||||
appContext.tabManager.openTabWithNoteWithHoisting(notePath);
|
||||
}
|
||||
else if (evt.which === 1) {
|
||||
else if (leftClick) {
|
||||
const ntxId = $(evt.target).closest("[data-ntx-id]").attr("data-ntx-id");
|
||||
|
||||
const noteContext = ntxId
|
||||
@@ -124,9 +127,12 @@ function goToLink(evt) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2
|
||||
|| $link.hasClass("ck-link-actions__preview") // within edit link dialog single click suffices
|
||||
|| $link.closest("[contenteditable]").length === 0 // outside of CKEditor single click suffices
|
||||
const withinEditLink = $link.hasClass("ck-link-actions__preview");
|
||||
const outsideOfCKEditor = $link.closest("[contenteditable]").length === 0;
|
||||
|
||||
if ((leftClick && ctrlKey) || middleClick
|
||||
|| (withinEditLink && (leftClick || middleClick))
|
||||
|| (outsideOfCKEditor && (leftClick || middleClick))
|
||||
) {
|
||||
if (address) {
|
||||
if (address.toLowerCase().startsWith('http')) {
|
||||
|
||||
@@ -2,7 +2,6 @@ import server from "./server.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
import utils from './utils.js';
|
||||
import noteCreateService from './note_create.js';
|
||||
import treeService from './tree.js';
|
||||
import froca from "./froca.js";
|
||||
|
||||
// this key needs to have this value, so it's hit by the tooltip
|
||||
@@ -188,7 +187,8 @@ function initNoteAutocomplete($el, options) {
|
||||
templateNoteId: templateNoteId
|
||||
});
|
||||
|
||||
suggestion.notePath = treeService.getSomeNotePath(note);
|
||||
const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||
suggestion.notePath = note.getBestNotePathString(hoistedNoteId);
|
||||
}
|
||||
|
||||
$el.setSelectedNotePath(suggestion.notePath);
|
||||
|
||||
@@ -157,9 +157,6 @@ async function getRenderedContent(note, options = {}) {
|
||||
$renderedContent.append($("<div>").text("Error parsing content. Please check console.error() for more details."));
|
||||
}
|
||||
}
|
||||
else if (type === 'book') {
|
||||
// nothing, book doesn't have its own content
|
||||
}
|
||||
else if (!options.tooltip && type === 'protectedSession') {
|
||||
const $button = $(`<button class="btn btn-sm"><span class="bx bx-log-in"></span> Enter protected session</button>`)
|
||||
.on('click', protectedSessionService.enterProtectedSession);
|
||||
@@ -172,7 +169,12 @@ async function getRenderedContent(note, options = {}) {
|
||||
);
|
||||
}
|
||||
else {
|
||||
$renderedContent.append($("<p><em>Content of this note cannot be displayed in the book format</em></p>"));
|
||||
$renderedContent.append(
|
||||
$("<div>")
|
||||
.css("text-align", "center")
|
||||
.css("font-size", "500%")
|
||||
.append($("<span>").addClass(note.getIcon()))
|
||||
);
|
||||
}
|
||||
|
||||
$renderedContent.addClass(note.getCssClass());
|
||||
|
||||
@@ -12,86 +12,93 @@ const TPL = `
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.note-list.grid-view .note-list-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.note-list.grid-view .note-book-card {
|
||||
flex-basis: 300px;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
|
||||
.note-list.grid-view .note-expander {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.note-list.grid-view .note-book-card {
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
.note-list.grid-view .note-book-card img {
|
||||
max-height: 220px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.note-list.grid-view .note-book-card:hover {
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--main-border-color);
|
||||
background: var(--more-accented-background-color);
|
||||
}
|
||||
|
||||
|
||||
.note-book-card {
|
||||
border-radius: 10px;
|
||||
background-color: var(--accented-background-color);
|
||||
padding: 10px 15px 15px 8px;
|
||||
margin: 5px 5px 5px 0;
|
||||
margin: 5px 5px 5px 5px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
.note-book-card:not(.expanded) .note-book-content {
|
||||
display: none !important;
|
||||
padding: 10px
|
||||
}
|
||||
|
||||
|
||||
.note-book-card.expanded .note-book-content {
|
||||
display: block;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.note-book-header {
|
||||
border-bottom: 1px solid var(--main-border-color);
|
||||
margin-bottom: 0;
|
||||
padding-bottom: .5rem;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
|
||||
/* not-expanded title is limited to one line only */
|
||||
.note-book-card:not(.expanded) .note-book-header {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.note-book-header .rendered-note-attributes {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
|
||||
.note-book-header .rendered-note-attributes:before {
|
||||
content: "\\00a0\\00a0";
|
||||
}
|
||||
|
||||
|
||||
.note-book-header .note-icon {
|
||||
font-size: 100%;
|
||||
display: inline-block;
|
||||
padding-right: 7px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.note-book-card .note-book-card {
|
||||
border: 1px solid var(--main-border-color);
|
||||
}
|
||||
|
||||
|
||||
.note-book-content.type-image, .note-book-content.type-file, .note-book-content.type-protectedSession {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -99,46 +106,46 @@ const TPL = `
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
.note-book-content.type-image img, .note-book-content.type-canvas svg {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
|
||||
.note-book-card.type-image .note-book-content img,
|
||||
.note-book-card.type-text .note-book-content img,
|
||||
.note-book-card.type-canvas .note-book-content img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.note-book-header {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
|
||||
.note-list-wrapper {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
.note-expander {
|
||||
font-size: x-large;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.note-list-pager {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="note-list-wrapper">
|
||||
<div class="note-list-pager"></div>
|
||||
|
||||
|
||||
<div class="note-list-container"></div>
|
||||
|
||||
|
||||
<div class="note-list-pager"></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
@@ -4,6 +4,7 @@ import froca from "./froca.js";
|
||||
import utils from "./utils.js";
|
||||
import attributeRenderer from "./attribute_renderer.js";
|
||||
import noteContentRenderer from "./note_content_renderer.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
|
||||
function setupGlobalTooltip() {
|
||||
$(document).on("mouseenter", "a", mouseEnterHandler);
|
||||
@@ -83,13 +84,14 @@ async function renderTooltip(note) {
|
||||
return '<div>Note has been deleted.</div>';
|
||||
}
|
||||
|
||||
const someNotePath = treeService.getSomeNotePath(note);
|
||||
const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||
const bestNotePath = note.getBestNotePathString(hoistedNoteId);
|
||||
|
||||
if (!someNotePath) {
|
||||
if (!bestNotePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
let content = `<h5 class="note-tooltip-title">${(await treeService.getNoteTitleWithPathAsSuffix(someNotePath)).prop('outerHTML')}</h5>`;
|
||||
let content = `<h5 class="note-tooltip-title">${(await treeService.getNoteTitleWithPathAsSuffix(bestNotePath)).prop('outerHTML')}</h5>`;
|
||||
|
||||
const {$renderedAttributes} = await attributeRenderer.renderNormalAttributes(note);
|
||||
|
||||
|
||||
@@ -47,6 +47,67 @@ async function openNoteExternally(noteId, mime) {
|
||||
}
|
||||
}
|
||||
|
||||
async function openNoteCustom(noteId) {
|
||||
if (!utils.isElectron() || utils.isMac()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const resp = await server.post(`notes/${noteId}/save-to-tmp-dir`);
|
||||
let filePath = resp.tmpFilePath;
|
||||
const {exec} = utils.dynamicRequire('child_process');
|
||||
const platform = process.platform;
|
||||
|
||||
if (platform === 'linux') {
|
||||
// we don't know which terminal is available, try in succession
|
||||
const terminals = ['x-terminal-emulator', 'gnome-terminal', 'konsole', 'xterm', 'xfce4-terminal', 'mate-terminal', 'rxvt', 'terminator', 'terminology'];
|
||||
const openFileWithTerminal = (terminal) => {
|
||||
const command = `${terminal} -e 'mimeopen -d "${filePath}"'`;
|
||||
console.log(`Open Note custom: ${command} `);
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`Open Note custom: Failed to open file with ${terminal}: ${error}`);
|
||||
searchTerminal(terminals.indexOf(terminal) + 1);
|
||||
} else {
|
||||
console.log(`Open Note custom: File opened with ${terminal}: ${stdout}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const searchTerminal = (index) => {
|
||||
const terminal = terminals[index];
|
||||
if (!terminal) {
|
||||
console.error('Open Note custom: No terminal found!');
|
||||
open(getFileUrl(noteId), {url: true});
|
||||
return;
|
||||
}
|
||||
exec(`which ${terminal}`, (error, stdout, stderr) => {
|
||||
if (stdout.trim()) {
|
||||
openFileWithTerminal(terminal);
|
||||
} else {
|
||||
searchTerminal(index + 1);
|
||||
}
|
||||
});
|
||||
};
|
||||
searchTerminal(0);
|
||||
} else if (platform === 'win32') {
|
||||
if (filePath.indexOf("/") !== -1) {
|
||||
// Note that the path separator must be \ instead of /
|
||||
filePath = filePath.replace(/\//g, "\\");
|
||||
}
|
||||
const command = `rundll32.exe shell32.dll,OpenAs_RunDLL ` + filePath;
|
||||
exec(command, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
console.error("Open Note custom: ", err);
|
||||
open(getFileUrl(noteId), {url: true});
|
||||
return;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('Currently "Open Note custom" only supports linux and windows systems');
|
||||
open(getFileUrl(noteId), {url: true});
|
||||
}
|
||||
}
|
||||
|
||||
function downloadNoteRevision(noteId, noteRevisionId) {
|
||||
const url = getUrlForDownload(`api/notes/${noteId}/revisions/${noteRevisionId}/download`);
|
||||
|
||||
@@ -76,6 +137,7 @@ export default {
|
||||
download,
|
||||
downloadFileNote,
|
||||
openNoteExternally,
|
||||
openNoteCustom,
|
||||
downloadNoteRevision,
|
||||
getUrlForDownload
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr
|
||||
return;
|
||||
}
|
||||
|
||||
child.resortParents();
|
||||
child.sortParents();
|
||||
|
||||
const parents = child.getParentNotes();
|
||||
|
||||
@@ -79,14 +79,10 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr
|
||||
You can ignore this message as it is mostly harmless.`);
|
||||
}
|
||||
|
||||
const someNotePath = getSomeNotePath(child, hoistedNoteId);
|
||||
const bestNotePath = child.getBestNotePath(hoistedNoteId);
|
||||
|
||||
if (someNotePath) { // in case it's root the path may be empty
|
||||
const pathToRoot = someNotePath.split("/").reverse().slice(1);
|
||||
|
||||
if (!pathToRoot.includes("root")) {
|
||||
pathToRoot.push('root');
|
||||
}
|
||||
if (bestNotePath) {
|
||||
const pathToRoot = bestNotePath.reverse().slice(1);
|
||||
|
||||
for (const noteId of pathToRoot) {
|
||||
effectivePathSegments.push(noteId);
|
||||
@@ -109,31 +105,17 @@ async function resolveNotePathToSegments(notePath, hoistedNoteId = 'root', logEr
|
||||
else {
|
||||
const note = await froca.getNote(getNoteIdFromNotePath(notePath));
|
||||
|
||||
const someNotePathSegments = getSomeNotePathSegments(note, hoistedNoteId);
|
||||
const bestNotePath = note.getBestNotePath(hoistedNoteId);
|
||||
|
||||
if (!someNotePathSegments) {
|
||||
throw new Error(`Did not find any path segments for ${note.toString()}, hoisted note ${hoistedNoteId}`);
|
||||
if (!bestNotePath) {
|
||||
throw new Error(`Did not find any path segments for '${note.toString()}', hoisted note '${hoistedNoteId}'`);
|
||||
}
|
||||
|
||||
// if there isn't actually any note path with hoisted note then return the original resolved note path
|
||||
return someNotePathSegments.includes(hoistedNoteId) ? someNotePathSegments : effectivePathSegments;
|
||||
return bestNotePath.includes(hoistedNoteId) ? bestNotePath : effectivePathSegments;
|
||||
}
|
||||
}
|
||||
|
||||
function getSomeNotePathSegments(note, hoistedNotePath = 'root') {
|
||||
utils.assertArguments(note);
|
||||
|
||||
const notePaths = note.getSortedNotePaths(hoistedNotePath);
|
||||
|
||||
return notePaths.length > 0 ? notePaths[0].notePath : null;
|
||||
}
|
||||
|
||||
function getSomeNotePath(note, hoistedNotePath = 'root') {
|
||||
const notePath = getSomeNotePathSegments(note, hoistedNotePath);
|
||||
|
||||
return notePath === null ? null : notePath.join('/');
|
||||
}
|
||||
|
||||
ws.subscribeToMessages(message => {
|
||||
if (message.type === 'openNote') {
|
||||
appContext.tabManager.activateOrOpenNote(message.noteId);
|
||||
@@ -311,16 +293,6 @@ function isNotePathInAddress() {
|
||||
|| (notePath === '' && !!ntxId);
|
||||
}
|
||||
|
||||
function parseNotePath(notePath) {
|
||||
let noteIds = notePath.split('/');
|
||||
|
||||
if (noteIds[0] !== 'root') {
|
||||
noteIds = ['root'].concat(noteIds);
|
||||
}
|
||||
|
||||
return noteIds;
|
||||
}
|
||||
|
||||
function isNotePathInHiddenSubtree(notePath) {
|
||||
return notePath?.includes("root/_hidden");
|
||||
}
|
||||
@@ -328,8 +300,6 @@ function isNotePathInHiddenSubtree(notePath) {
|
||||
export default {
|
||||
resolveNotePath,
|
||||
resolveNotePathToSegments,
|
||||
getSomeNotePath,
|
||||
getSomeNotePathSegments,
|
||||
getParentProtectedStatus,
|
||||
getNotePath,
|
||||
getNoteIdFromNotePath,
|
||||
@@ -340,6 +310,5 @@ export default {
|
||||
getNoteTitleWithPathAsSuffix,
|
||||
getHashValueFromAddress,
|
||||
isNotePathInAddress,
|
||||
parseNotePath,
|
||||
isNotePathInHiddenSubtree
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ function formatTimeWithSeconds(date) {
|
||||
|
||||
// this is producing local time!
|
||||
function formatDate(date) {
|
||||
// return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
|
||||
// return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
|
||||
// instead of european format we'll just use ISO as that's pretty unambiguous
|
||||
|
||||
return formatDateISO(date);
|
||||
@@ -45,7 +45,7 @@ function formatDateTime(date) {
|
||||
}
|
||||
|
||||
function localNowDateTime() {
|
||||
return dayjs().format('YYYY-MM-DD HH:mm:ss.SSSZZ')
|
||||
return dayjs().format('YYYY-MM-DD HH:mm:ss.SSSZZ');
|
||||
}
|
||||
|
||||
function now() {
|
||||
@@ -101,7 +101,7 @@ async function stopWatch(what, func) {
|
||||
}
|
||||
|
||||
function formatValueWithWhitespace(val) {
|
||||
return /[^\w_-]/.test(val) ? `"${val}"` : val;
|
||||
return /[^\w-]/.test(val) ? `"${val}"` : val;
|
||||
}
|
||||
|
||||
function formatLabel(label) {
|
||||
@@ -318,7 +318,7 @@ function initHelpDropdown($el) {
|
||||
initHelpButtons($dropdownMenu);
|
||||
}
|
||||
|
||||
const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/"
|
||||
const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/";
|
||||
|
||||
function openHelp(e) {
|
||||
window.open(wikiBaseUrl + $(e.target).attr("data-help-page"), '_blank');
|
||||
@@ -329,7 +329,7 @@ function initHelpButtons($el) {
|
||||
// so we do it manually
|
||||
$el.on("click", e => {
|
||||
if ($(e.target).attr("data-help-page")) {
|
||||
openHelp(e)
|
||||
openHelp(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -354,6 +354,17 @@ function escapeRegExp(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
|
||||
}
|
||||
|
||||
function formatNoteSize(size) {
|
||||
size = Math.max(Math.round(size / 1024), 1);
|
||||
|
||||
if (size < 1024) {
|
||||
return `${size} KiB`;
|
||||
}
|
||||
else {
|
||||
return `${Math.round(size / 102.4) / 10} MiB`;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
reloadFrontendApp,
|
||||
parseDate,
|
||||
@@ -396,5 +407,6 @@ export default {
|
||||
filterAttributeName,
|
||||
isValidAttributeName,
|
||||
sleep,
|
||||
escapeRegExp
|
||||
escapeRegExp,
|
||||
formatNoteSize
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import server from "../../services/server.js";
|
||||
import froca from "../../services/froca.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
import linkService from "../../services/link.js";
|
||||
import attributeAutocompleteService from "../../services/attribute_autocomplete.js";
|
||||
import noteAutocompleteService from "../../services/note_autocomplete.js";
|
||||
@@ -9,6 +8,7 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
import SpacedUpdate from "../../services/spaced_update.js";
|
||||
import utils from "../../services/utils.js";
|
||||
import shortcutService from "../../services/shortcuts.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="attr-detail">
|
||||
@@ -242,7 +242,8 @@ const ATTR_HELP = {
|
||||
"keepCurrentHoisting": "Opening this link won't change hoisting even if the note is not displayable in the current hoisted subtree.",
|
||||
"executeButton": "Title of the button which will execute the current code note",
|
||||
"executeDescription": "Longer description of the current code note displayed together with the execute button",
|
||||
"excludeFromNoteMap": "Notes with this label will be hidden from the Note Map"
|
||||
"excludeFromNoteMap": "Notes with this label will be hidden from the Note Map",
|
||||
"newNotesOnTop": "New notes will be created at the top of the parent note, not on the bottom."
|
||||
},
|
||||
"relation": {
|
||||
"runOnNoteCreation": "executes when note is created on backend. Use this relation if you want to run the script for all notes created under a specific subtree. In that case, create it on the subtree root note and make it inheritable. A new note created within the subtree (any depth) will trigger the script.",
|
||||
@@ -284,7 +285,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
|
||||
this.$title = this.$widget.find('.attr-detail-title');
|
||||
|
||||
this.$inputName = this.$widget.find('.attr-input-name');
|
||||
this.$inputName.on('keyup', () => this.userEditedAttribute());
|
||||
this.$inputName.on('input', ev => {
|
||||
if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
|
||||
this.userEditedAttribute();
|
||||
}
|
||||
});
|
||||
this.$inputName.on('change', () => this.userEditedAttribute());
|
||||
this.$inputName.on('autocomplete:closed', () => this.userEditedAttribute());
|
||||
|
||||
@@ -298,7 +303,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
|
||||
|
||||
this.$rowValue = this.$widget.find('.attr-row-value');
|
||||
this.$inputValue = this.$widget.find('.attr-input-value');
|
||||
this.$inputValue.on('keyup', () => this.userEditedAttribute());
|
||||
this.$inputValue.on('input', ev => {
|
||||
if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
|
||||
this.userEditedAttribute();
|
||||
}
|
||||
});
|
||||
this.$inputValue.on('change', () => this.userEditedAttribute());
|
||||
this.$inputValue.on('autocomplete:closed', () => this.userEditedAttribute());
|
||||
this.$inputValue.on('focus', () => {
|
||||
@@ -327,7 +336,11 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
|
||||
|
||||
this.$rowInverseRelation = this.$widget.find('.attr-row-inverse-relation');
|
||||
this.$inputInverseRelation = this.$widget.find('.attr-input-inverse-relation');
|
||||
this.$inputInverseRelation.on('keyup', () => this.userEditedAttribute());
|
||||
this.$inputInverseRelation.on('input', ev => {
|
||||
if (!ev.originalEvent?.isComposing) { // https://github.com/zadam/trilium/pull/3812
|
||||
this.userEditedAttribute();
|
||||
}
|
||||
});
|
||||
|
||||
this.$rowTargetNote = this.$widget.find('.attr-row-target-note');
|
||||
this.$inputTargetNote = this.$widget.find('.attr-input-target-note');
|
||||
@@ -585,9 +598,10 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
|
||||
|
||||
const displayedResults = results.length <= DISPLAYED_NOTES ? results : results.slice(0, DISPLAYED_NOTES);
|
||||
const displayedNotes = await froca.getNotes(displayedResults.map(res => res.noteId));
|
||||
const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||
|
||||
for (const note of displayedNotes) {
|
||||
const notePath = treeService.getSomeNotePath(note);
|
||||
const notePath = note.getBestNotePathString(hoistedNoteId);
|
||||
const $noteLink = await linkService.createNoteLink(notePath, {showNotePath: true});
|
||||
|
||||
this.$relatedNotesList.append(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user