Compare commits
77 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 420175f5ef | |||
| bdfdc0402d | |||
| bb8496cb3f | |||
| 4bdb94fbaa | |||
| 5bf9c253f2 | |||
| b0cc177d84 | |||
| c60f25fb7c | |||
| 571cb6d0eb | |||
| f738787202 | |||
| 4ae1b6e07b | |||
| 41b8f6882c | |||
| 43c5163f66 | |||
| 8a2a9b2ea6 | |||
| c70272e756 | |||
| 843f5d0da1 | |||
| f86fb0d0a2 | |||
| 218f526a92 | |||
| 161b45aa12 | |||
| 397629587c | |||
| 034098fd06 | |||
| e03cc01e15 | |||
| 0995c56506 | |||
| 3a5fa2954d | |||
| 398480415e | |||
| 81013ed21a | |||
| 53360c147a | |||
| 9e47da3f03 | |||
| faefe10c15 | |||
| a4d3150a24 | |||
| e1f0676891 | |||
| 792ac9b77d | |||
| bbbd2f7e82 | |||
| d910191e83 | |||
| e8a9389e6d | |||
| 6dce13bc34 | |||
| 71cdea3902 | |||
| 85a6e8b47e | |||
| f02ad63e97 | |||
| 977399a73e | |||
| 291ef87c9b | |||
| 115bf0af4d | |||
| e40f1fd11a | |||
| 797ddf6205 | |||
| ca4e1c19a7 | |||
| dd82b0f958 | |||
| f150c223bc | |||
| 4f771cfa7a | |||
| aa3b26c965 | |||
| f4cf04232f | |||
| d36cf47974 | |||
| f809da58ec | |||
| ff1f01be8c | |||
| 0ddaa8f5c2 | |||
| 620bed73bb | |||
| c177d2b97b | |||
| 0758c82983 | |||
| ecc2ed7d73 | |||
| 4b779d7512 | |||
| 701911b766 | |||
| 7a8bbdced8 | |||
| affd8062e2 | |||
| 2cfc43a4fd | |||
| fb789b7bd8 | |||
| b906efb23b | |||
| f249d6cb26 | |||
| afb6e860ea | |||
| 435e042ae9 | |||
| d64df5e3e7 | |||
| bd59802ca4 | |||
| 7c98ade72b | |||
| c6485f8e03 | |||
| a083917db1 | |||
| c409d7ff2a | |||
| f8dd175837 | |||
| df3212c304 | |||
| 6ec734df13 | |||
| 102bfcebd0 |
@@ -11,3 +11,4 @@ cert.crt
|
||||
server-package.json
|
||||
.idea/httpRequests/
|
||||
data/
|
||||
tmp/
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ image:
|
||||
file: .gitpod.dockerfile
|
||||
|
||||
tasks:
|
||||
- before: nvm install 16.18.0 && nvm use 16.18.0
|
||||
- before: nvm install 16.19.0 && nvm use 16.19.0
|
||||
init: npm install
|
||||
command: npm run start-server
|
||||
|
||||
|
||||
Vendored
+2
-1
@@ -9,7 +9,8 @@
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"env": {
|
||||
"TRILIUM_ENV": "dev"
|
||||
"TRILIUM_ENV": "dev",
|
||||
"TRILIUM_DATA_DIR": "./data"
|
||||
},
|
||||
"outputCapture": "std",
|
||||
"program": "${workspaceFolder}/src/www"
|
||||
|
||||
+2
-6
@@ -1,5 +1,5 @@
|
||||
# !!! Don't try to build this Dockerfile directly, run it through bin/build-docker.sh script !!!
|
||||
FROM node:16.18.0-alpine
|
||||
FROM node:16.19.0-alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
@@ -25,12 +25,8 @@ RUN set -x \
|
||||
&& apk del .build-dependencies \
|
||||
&& npm run webpack \
|
||||
&& npm prune --omit=dev \
|
||||
# Set the path to the newly created webpack bundle
|
||||
&& sed -i -e 's/app\/desktop.js/app-dist\/desktop.js/g' src/views/desktop.ejs \
|
||||
&& sed -i -e 's/app\/mobile.js/app-dist\/mobile.js/g' src/views/mobile.ejs \
|
||||
&& sed -i -e 's/app\/setup.js/app-dist\/setup.js/g' src/views/setup.ejs \
|
||||
&& sed -i -e 's/app\/share.js/app-dist\/share.js/g' src/views/share/*.ejs \
|
||||
&& cp src/public/app/share.js src/public/app-dist/. \
|
||||
&& cp -r src/public/app/doc_notes src/public/app-dist/. \
|
||||
&& rm -rf src/public/app
|
||||
|
||||
# Some setup tools need to be kept
|
||||
|
||||
+35
-20
@@ -1,9 +1,9 @@
|
||||
# Trilium笔记
|
||||
# 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)
|
||||
Trilium Notes是一个分层的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://github.com/zadam/trilium/wiki/Screenshot-tour)以快速了解:
|
||||
Trilium Notes 是一个层次化的笔记应用程序,专注于建立大型个人知识库。请参阅[屏幕截图](https://github.com/zadam/trilium/wiki/Screenshot-tour)以快速了解:
|
||||
|
||||

|
||||
|
||||
@@ -14,36 +14,43 @@ Ukraine is currently suffering from Russian aggression, please consider donating
|
||||
## 特性
|
||||
|
||||
* 笔记可以排列成任意深的树。单个笔记可以放在树中的多个位置(请参阅[克隆](https://github.com/zadam/trilium/wiki/Cloning-notes))
|
||||
* 丰富的所见即所得笔记编辑功能,包括带有markdown[自动格式化功能的](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)表格,图像和[数学](https://github.com/zadam/trilium/wiki/Text-notes#math-support)
|
||||
* 丰富的所见即所得笔记编辑功能,包括带有 Markdown [自动格式化功能的](https://github.com/zadam/trilium/wiki/Text-notes#autoformat)表格,图像和[数学](https://github.com/zadam/trilium/wiki/Text-notes#math-support)
|
||||
* 支持编辑[使用源代码的笔记](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-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)
|
||||
* 可用性和性能均能很好地扩展至超过10万个笔记
|
||||
* 针对智能手机和平板电脑进行触摸优化的[移动前端](https://github.com/zadam/trilium/wiki/Mobile-frontend)
|
||||
* [脚本](https://github.com/zadam/trilium/wiki/Scripts) - 请参阅[高级功能展示](https://github.com/zadam/trilium/wiki/Advanced-showcases)
|
||||
* 在拥有超过 10 万条笔记时仍能保持良好的可用性和性能
|
||||
* 针对智能手机和平板电脑进行优化的[用于移动设备的前端](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 Clipper](https://github.com/zadam/trilium/wiki/Web-clipper)可轻松保存Web内容
|
||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) 和 [Markdown 导入导出](https://github.com/zadam/trilium/wiki/Markdown)功能
|
||||
* 使用[网页剪藏](https://github.com/zadam/trilium/wiki/Web-clipper)轻松保存互联网上的内容
|
||||
|
||||
## 构建
|
||||
|
||||
Trilium是作为桌面应用程序(Linux和Windows)或服务器上托管的Web应用程序(Linux)提供的。Mac OS桌面版本可用,但[不受支持](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support)。
|
||||
Trilium 可以用作桌面应用程序(Linux 和 Windows)或服务器(Linux)上托管的 Web 应用程序。虽然有 macOS 版本的桌面应用程序,但它[不受支持](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support)。
|
||||
|
||||
* 如果要在桌面上使用Trilium,请从[最新版本](https://github.com/zadam/trilium/releases/latest)下载适用于您平台的二进制[版本](https://github.com/zadam/trilium/releases/latest),解压缩该软件包并运行`trilium`可执行文件。
|
||||
* 如果要在服务器上安装Trilium,请遵循[此页面](https://github.com/zadam/trilium/wiki/Server-installation)。
|
||||
* 当前仅支持(经过测试)最新的Chrome和Firefox浏览器。
|
||||
* 如果要在桌面上使用 Trilium,请从[最新版本](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/)
|
||||
[有关文档页面的完整列表,请参见 Wiki。](https://github.com/zadam/trilium/wiki/)
|
||||
|
||||
[中文Wiki在这里](https://github.com/baddate/trilium/wiki/)
|
||||
* [Wiki 的中文翻译版本](https://github.com/baddate/trilium/wiki/)
|
||||
|
||||
您还可以阅读[个人知识库模式](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base),以获取有关如何使用Trilium的灵感。
|
||||
您还可以阅读[个人知识库模式](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base),以获取有关如何使用 Trilium 的灵感。
|
||||
|
||||
## 贡献
|
||||
|
||||
@@ -51,7 +58,7 @@ Trilium是作为桌面应用程序(Linux和Windows)或服务器上托管的W
|
||||
|
||||
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||
|
||||
或在本地克隆并运行
|
||||
或者克隆本仓库到本地,并运行
|
||||
|
||||
```
|
||||
npm install
|
||||
@@ -60,7 +67,15 @@ npm run start-server
|
||||
|
||||
## 致谢
|
||||
|
||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - 市场上最好的所见即所得编辑器,互动性强且聆听能力强的团队
|
||||
* [FancyTree](https://github.com/mar10/fancytree) - 一个非常丰富的关于树的库,强大的没有对手。没有它,Trilium Notes将不会如此。
|
||||
* [CKEditor 5](https://github.com/ckeditor/ckeditor5) - 市面上最好的所见即所得编辑器,拥有互动性强且聆听能力强的团队
|
||||
* [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)
|
||||
* [jsPlumb](https://github.com/jsplumb/jsplumb) - 强大的可视化连接库。用于[关系图](https://github.com/zadam/trilium/wiki/Relation-map)和[链接图](https://github.com/zadam/trilium/wiki/Link-map)
|
||||
|
||||
## 捐赠
|
||||
|
||||
你可以通过 GitHub Sponsors,[PayPal](https://paypal.me/za4am) 或者比特币 (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2) 来捐赠。
|
||||
|
||||
## 许可证
|
||||
|
||||
本程序是自由软件:你可以再发布本软件和/或修改本软件,只要你遵循 Free Software Foundation 发布的 GNU Affero General Public License 的第三版或者任何(由你选择)更晚的版本。
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PKG_DIR=dist/trilium-linux-x64-server
|
||||
NODE_VERSION=16.18.0
|
||||
NODE_VERSION=16.19.0
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
|
||||
+3
-7
@@ -5,7 +5,7 @@ if [[ $# -eq 0 ]] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
n exec 16.18.0 npm run webpack
|
||||
n exec 16.19.0 npm run webpack
|
||||
|
||||
DIR=$1
|
||||
|
||||
@@ -27,7 +27,7 @@ cp -r electron.js $DIR/
|
||||
cp webpack-* $DIR/
|
||||
|
||||
# run in subshell (so we return to original dir)
|
||||
(cd $DIR && n exec 16.18.0 npm install --only=prod)
|
||||
(cd $DIR && n exec 16.19.0 npm install --only=prod)
|
||||
|
||||
# cleanup of useless files in dependencies
|
||||
rm -r $DIR/node_modules/image-q/demo
|
||||
@@ -45,10 +45,6 @@ find $DIR/node_modules -name demo -exec rm -rf {} \;
|
||||
find $DIR/libraries -name "*.map" -type f -delete
|
||||
|
||||
cp $DIR/src/public/app/share.js $DIR/src/public/app-dist/
|
||||
cp -r $DIR/src/public/app/doc_notes $DIR/src/public/app-dist/
|
||||
|
||||
rm -rf $DIR/src/public/app
|
||||
|
||||
sed -i -e 's/app\/desktop.js/app-dist\/desktop.js/g' $DIR/src/views/desktop.ejs
|
||||
sed -i -e 's/app\/mobile.js/app-dist\/mobile.js/g' $DIR/src/views/mobile.ejs
|
||||
sed -i -e 's/app\/setup.js/app-dist\/setup.js/g' $DIR/src/views/setup.ejs
|
||||
sed -i -e 's/app\/share.js/app-dist\/share.js/g' $DIR/src/views/share/*.ejs
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
-- "randomize" branchIds so it's clear user should not rely on them
|
||||
UPDATE branches SET branchId = '7LSsI2FnZPW2' WHERE parentNoteId = 'hidden' AND noteId = 'search';
|
||||
UPDATE branches SET branchId = 'wEcmxk4CNC7G' WHERE parentNoteId = 'singles' AND noteId = 'globalnotemap';
|
||||
UPDATE branches SET branchId = '191uVR6Cu6fA' WHERE parentNoteId = 'hidden' AND noteId = 'sqlconsole';
|
||||
UPDATE branches SET branchId = 'OjX5Phxp6A4N' WHERE parentNoteId = 'root' AND noteId = 'hidden';
|
||||
UPDATE branches SET branchId = 'glNBYFYZRH8P' WHERE parentNoteId = 'hidden' AND noteId = 'bulkaction';
|
||||
UPDATE branches SET branchId = 'cAT25wvGMg3K' WHERE parentNoteId = 'root' AND noteId = 'share';
|
||||
@@ -0,0 +1,6 @@
|
||||
UPDATE branches SET branchId = '_hidden__search' WHERE parentNoteId = 'hidden' AND noteId = 'search';
|
||||
UPDATE branches SET branchId = 'root__globalNoteMap' WHERE parentNoteId = 'singles' AND noteId = 'globalnotemap';
|
||||
UPDATE branches SET branchId = '_hidden__sqlConsole' WHERE parentNoteId = 'hidden' AND noteId = 'sqlconsole';
|
||||
UPDATE branches SET branchId = 'root__hidden' WHERE parentNoteId = 'root' AND noteId = 'hidden';
|
||||
UPDATE branches SET branchId = '_hidden__bulkAction' WHERE parentNoteId = 'hidden' AND noteId = 'bulkaction';
|
||||
UPDATE branches SET branchId = '_hidden__share' WHERE parentNoteId = 'root' AND noteId = 'share';
|
||||
@@ -1,2 +1,2 @@
|
||||
DELETE FROM branches WHERE noteId = '_globalNoteMap' AND parentNoteId != 'singles'; -- make sure there are no clones which would fail at the next line
|
||||
DELETE FROM branches WHERE noteId = '_globalNoteMap' AND parentNoteId != 'singles' AND parentNoteId != '_hidden'; -- make sure there are no clones which would fail at the next line
|
||||
UPDATE branches SET parentNoteId = '_hidden' WHERE noteId = '_globalNoteMap';
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
module.exports = async () => {
|
||||
const cls = require("../../src/services/cls");
|
||||
const beccaLoader = require("../../src/becca/becca_loader");
|
||||
const log = require("../../src/services/log");
|
||||
const consistencyChecks = require("../../src/services/consistency_checks");
|
||||
const noteService = require("../../src/services/notes");
|
||||
|
||||
await cls.init(async () => {
|
||||
// precaution for the 0211 migration
|
||||
noteService.eraseDeletedNotesNow();
|
||||
|
||||
beccaLoader.load();
|
||||
|
||||
try {
|
||||
// precaution before running 211 which might produce unique constraint problems if the DB was not consistent
|
||||
consistencyChecks.runOnDemandChecksWithoutExclusiveLock(true);
|
||||
}
|
||||
catch (e) {
|
||||
// consistency checks might start failing in the future if there's some incompatible migration down the road
|
||||
// we can optimistically assume the DB is consistent and still continue
|
||||
log.error(`Consistency checks failed in migration 0210: ${e.message} ${e.stack}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
-- case based on isDeleted is needed, otherwise 2 branches (1 deleted, 1 not) might get the same ID
|
||||
UPDATE entity_changes SET entityId = COALESCE((
|
||||
SELECT
|
||||
CASE isDeleted
|
||||
WHEN 0 THEN parentNoteId || '_' || noteId
|
||||
WHEN 1 THEN branchId
|
||||
END
|
||||
FROM branches WHERE branchId = entityId
|
||||
), entityId)
|
||||
WHERE entityName = 'branches' AND isErased = 0;
|
||||
|
||||
UPDATE branches SET branchId = parentNoteId || '_' || noteId WHERE isDeleted = 0;
|
||||
@@ -0,0 +1,21 @@
|
||||
module.exports = () => {
|
||||
const cls = require("../../src/services/cls");
|
||||
const beccaLoader = require("../../src/becca/becca_loader");
|
||||
const becca = require("../../src/becca/becca");
|
||||
|
||||
cls.init(() => {
|
||||
beccaLoader.load();
|
||||
|
||||
const hidden = becca.getNote("_hidden");
|
||||
|
||||
for (const noteId of hidden.getSubtreeNoteIds({includeHidden: true})) {
|
||||
if (noteId.startsWith("_")) { // is "named" note
|
||||
const note = becca.getNote(noteId);
|
||||
|
||||
for (const attr of note.getOwnedAttributes()) {
|
||||
attr.markAsDeleted("0212__delete_all_attributes_of_named_notes");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -94,7 +94,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line15">line 15</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line16">line 16</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line46">line 46</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line47">line 47</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line58">line 58</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line59">line 59</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line52">line 52</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line53">line 53</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -472,7 +472,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line48">line 48</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line49">line 49</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -540,7 +540,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line54">line 54</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line55">line 55</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -608,7 +608,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line50">line 50</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line51">line 51</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -676,7 +676,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line60">line 60</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line61">line 61</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -744,7 +744,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line56">line 56</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line57">line 57</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1176,7 +1176,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line130">line 130</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line129">line 129</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1370,7 +1370,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line143">line 143</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line142">line 142</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1564,7 +1564,7 @@ and relation (representing named relationship between source and target note)</d
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line158">line 158</a>
|
||||
<a href="becca_entities_attribute.js.html">becca/entities/attribute.js</a>, <a href="becca_entities_attribute.js.html#line157">line 157</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line547">line 547</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line570">line 570</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -735,7 +735,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line449">line 449</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line472">line 472</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1743,7 +1743,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line485">line 485</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line508">line 508</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2460,7 +2460,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line437">line 437</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line460">line 460</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2566,7 +2566,7 @@ JSON MIME type. See also createNewNote() for more options.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line462">line 462</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line485">line 485</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5150,7 +5150,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_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line430">line 430</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line453">line 453</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5258,7 +5258,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_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line455">line 455</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line478">line 478</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5850,7 +5850,187 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line411">line 411</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line434">line 434</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="sortNotes"><span class="type-signature"></span>sortNotes<span class="signature">(parentNoteId, sortConfig<span class="signature-attributes">opt</span>)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Sort child notes of a given note.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
<th>Attributes</th>
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>parentNoteId</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">this note's child notes will be sorted</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>sortConfig</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="global.html#SortConfig">SortConfig</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line415">line 415</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5971,6 +6151,8 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>- use sortNotes instead</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5983,7 +6165,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line397">line 397</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line398">line 398</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6345,7 +6527,7 @@ exists, then we'll use that transaction.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line421">line 421</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line444">line 444</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6500,7 +6682,7 @@ exists, then we'll use that transaction.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line444">line 444</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line467">line 467</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>Branch<span class="signature">()</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
|
||||
parents.</div>
|
||||
parents.
|
||||
|
||||
Note that you should not rely on the branch's identity, since it can change easily with a note's move.
|
||||
Always check noteId instead.</div>
|
||||
|
||||
|
||||
</header>
|
||||
@@ -94,7 +97,7 @@ parents.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line18">line 18</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line20">line 20</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -268,7 +271,7 @@ parents.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line49">line 49</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line51">line 51</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -326,7 +329,7 @@ parents.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line95">line 95</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line97">line 97</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -394,7 +397,7 @@ parents.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line59">line 59</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line61">line 61</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -460,7 +463,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line131">line 131</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line133">line 133</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -528,7 +531,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line51">line 51</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line53">line 53</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -596,7 +599,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line57">line 57</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line59">line 59</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -654,7 +657,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line109">line 109</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line111">line 111</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -722,7 +725,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line53">line 53</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line55">line 55</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -790,7 +793,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line55">line 55</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line57">line 57</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -858,7 +861,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line61">line 61</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line63">line 63</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1210,7 +1213,7 @@ of deletion should not act as a clone.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line143">line 143</a>
|
||||
<a href="becca_entities_branch.js.html">becca/entities/branch.js</a>, <a href="becca_entities_branch.js.html#line145">line 145</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
+21
-21
@@ -1226,7 +1226,7 @@ See addLabel, addRelation for more specific methods.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1174">line 1174</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1177">line 1177</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1513,7 +1513,7 @@ See addLabel, addRelation for more specific methods.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1195">line 1195</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1198">line 1198</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1692,7 +1692,7 @@ returned.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1208">line 1208</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1211">line 1211</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1927,7 +1927,7 @@ returned.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1293">line 1293</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1296">line 1296</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2127,7 +2127,7 @@ returned.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1307">line 1307</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1310">line 1310</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2389,7 +2389,7 @@ returned.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1089">line 1089</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1092">line 1092</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2495,7 +2495,7 @@ returned.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1009">line 1009</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1008">line 1008</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7411,7 +7411,7 @@ This method can be significantly faster than the getAttribute()
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line950">line 950</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line949">line 949</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7615,7 +7615,7 @@ This method can be significantly faster than the getAttribute()
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1051">line 1051</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1054">line 1054</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7811,7 +7811,7 @@ This method can be significantly faster than the getAttribute()
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1035">line 1035</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1034">line 1034</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -9306,7 +9306,7 @@ This method can be significantly faster than the getAttribute()
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1110">line 1110</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1113">line 1113</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -10228,7 +10228,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1154">line 1154</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1157">line 1157</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -10408,7 +10408,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1269">line 1269</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1272">line 1272</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -10588,7 +10588,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1277">line 1277</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1280">line 1280</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -10783,7 +10783,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1359">line 1359</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1362">line 1362</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -11015,7 +11015,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1123">line 1123</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1126">line 1126</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -11195,7 +11195,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1253">line 1253</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1256">line 1256</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -11355,7 +11355,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1261">line 1261</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1264">line 1264</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -11597,7 +11597,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1220">line 1220</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1223">line 1223</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -11808,7 +11808,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1236">line 1236</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1239">line 1239</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -12019,7 +12019,7 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1245">line 1245</a>
|
||||
<a href="becca_entities_note.js.html">becca/entities/note.js</a>, <a href="becca_entities_note.js.html#line1248">line 1248</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ const AbstractEntity = require("./abstract_entity");
|
||||
const sql = require("../../services/sql");
|
||||
const dateUtils = require("../../services/date_utils");
|
||||
const promotedAttributeDefinitionParser = require("../../services/promoted_attribute_definition_parser");
|
||||
const {sanitizeAttributeName} = require("../../services/sanitize_attribute_name");
|
||||
|
||||
/**
|
||||
* Attribute is an abstract concept which has two real uses - label (key - value pair)
|
||||
@@ -91,8 +92,6 @@ class Attribute extends AbstractEntity {
|
||||
}
|
||||
|
||||
init() {
|
||||
this.validate();
|
||||
|
||||
if (this.attributeId) {
|
||||
this.becca.attributes[this.attributeId] = this;
|
||||
}
|
||||
@@ -208,6 +207,8 @@ class Attribute extends AbstractEntity {
|
||||
beforeSaving() {
|
||||
this.validate();
|
||||
|
||||
this.name = sanitizeAttributeName(this.name);
|
||||
|
||||
if (!this.value) {
|
||||
// null value isn't allowed
|
||||
this.value = "";
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
const Note = require('./note');
|
||||
const AbstractEntity = require("./abstract_entity");
|
||||
const sql = require("../../services/sql");
|
||||
const dateUtils = require("../../services/date_utils");
|
||||
const utils = require("../../services/utils");
|
||||
const TaskContext = require("../../services/task_context");
|
||||
@@ -41,6 +40,9 @@ const log = require("../../services/log");
|
||||
* Branch represents a relationship between a child note and its parent note. Trilium allows a note to have multiple
|
||||
* parents.
|
||||
*
|
||||
* Note that you should not rely on the branch's identity, since it can change easily with a note's move.
|
||||
* Always check noteId instead.
|
||||
*
|
||||
* @extends AbstractEntity
|
||||
*/
|
||||
class Branch extends AbstractEntity {
|
||||
@@ -157,7 +159,7 @@ class Branch extends AbstractEntity {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get isWeak() {
|
||||
return ['_share', 'lbBookmarks'].includes(this.parentNoteId);
|
||||
return ['_share', '_lbBookmarks'].includes(this.parentNoteId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +241,7 @@ class Branch extends AbstractEntity {
|
||||
let maxNotePos = 0;
|
||||
|
||||
for (const childBranch of this.parentNote.getChildBranches()) {
|
||||
if (maxNotePos < childBranch.notePosition && childBranch.branchId !== '_hidden') {
|
||||
if (maxNotePos < childBranch.notePosition && childBranch.noteId !== '_hidden') {
|
||||
maxNotePos = childBranch.notePosition;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,7 +915,7 @@ class Note extends AbstractEntity {
|
||||
/**
|
||||
* @returns {{notes: Note[], relationships: Array.<{parentNoteId: string, childNoteId: string}>}}
|
||||
*/
|
||||
getSubtree({includeArchived = true, resolveSearch = false} = {}) {
|
||||
getSubtree({includeArchived = true, includeHidden = false, resolveSearch = false} = {}) {
|
||||
const noteSet = new Set();
|
||||
const relationships = []; // list of tuples parentNoteId -> childNoteId
|
||||
|
||||
@@ -931,8 +931,7 @@ class Note extends AbstractEntity {
|
||||
}
|
||||
|
||||
function addSubtreeNotesInner(note, parentNote = null) {
|
||||
// share can be removed after 0.57 since it will be put under hidden
|
||||
if (note.noteId === '_hidden' || note.noteId === '_share') {
|
||||
if (note.noteId === '_hidden' && !includeHidden) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1070,6 +1069,10 @@ class Note extends AbstractEntity {
|
||||
return false;
|
||||
}
|
||||
|
||||
isInHiddenSubtree() {
|
||||
return this.noteId === '_hidden' || this.hasAncestor('_hidden');
|
||||
}
|
||||
|
||||
getTargetRelations() {
|
||||
return this.targetRelations;
|
||||
}
|
||||
|
||||
@@ -1468,7 +1468,220 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line464">line 464</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line487">line 487</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="SortConfig">SortConfig</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">Object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
<th>Attributes</th>
|
||||
|
||||
|
||||
|
||||
<th>Default</th>
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>sortBy</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
title
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">'title', 'dateCreated', 'dateModified' or a label name
|
||||
see https://github.com/zadam/trilium/wiki/Sorting for details.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>reverse</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">boolean</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
false
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>foldersFirst</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">boolean</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
false
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line400">line 400</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -420,10 +420,33 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @deprecated - use sortNotes instead
|
||||
* @param {string} parentNoteId - this note's child notes will be sorted
|
||||
*/
|
||||
this.sortNotesByTitle = parentNoteId => treeService.sortNotes(parentNoteId);
|
||||
|
||||
/**
|
||||
* @typedef {Object} SortConfig
|
||||
* @property {string} [sortBy=title] - 'title', 'dateCreated', 'dateModified' or a label name
|
||||
* see https://github.com/zadam/trilium/wiki/Sorting for details.
|
||||
* @property {boolean} [reverse=false]
|
||||
* @property {boolean} [foldersFirst=false]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sort child notes of a given note.
|
||||
*
|
||||
* @method
|
||||
* @param {string} parentNoteId - this note's child notes will be sorted
|
||||
* @param {SortConfig} [sortConfig]
|
||||
*/
|
||||
this.sortNotes = (parentNoteId, sortConfig = {}) => treeService.sortNotes(
|
||||
parentNoteId,
|
||||
sortConfig.sortBy || "title",
|
||||
!!sortConfig.reverse,
|
||||
!!sortConfig.foldersFirst
|
||||
);
|
||||
|
||||
/**
|
||||
* This method finds note by its noteId and prefix and either sets it to the given parentNoteId
|
||||
* or removes the branch (if parentNoteId is not given).
|
||||
@@ -521,12 +544,12 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
if (opts.type === 'customWidget' && !opts.widgetNoteId) { throw new Error("widgetNoteId is mandatory for launchers of type 'customWidget'"); }
|
||||
|
||||
const parentNoteId = !!opts.isVisible ? '_lbVisibleLaunchers' : '_lbAvailableLaunchers';
|
||||
const actualId = 'al_' + opts.id;
|
||||
const noteId = 'al_' + opts.id;
|
||||
|
||||
const launcherNote =
|
||||
becca.getNote(opts.id) ||
|
||||
specialNotesService.createLauncher({
|
||||
id: actualId,
|
||||
noteId: noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
launcherType: opts.type,
|
||||
}).note;
|
||||
|
||||
@@ -2582,7 +2582,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line744">line 744</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line748">line 748</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5400,7 +5400,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line788">line 788</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line792">line 792</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5513,7 +5513,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line733">line 733</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line737">line 737</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -5619,7 +5619,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line723">line 723</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line727">line 727</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6903,7 +6903,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line716">line 716</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line720">line 720</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -6987,7 +6987,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line783">line 783</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line787">line 787</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -7093,7 +7093,7 @@ This note's representation is used in note tree and is kept in Froca.</div>
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line775">line 775</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line779">line 779</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -738,6 +738,10 @@ class NoteShort {
|
||||
return false;
|
||||
}
|
||||
|
||||
isInHiddenSubtree() {
|
||||
return this.noteId === '_hidden' || this.hasAncestor('_hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated NOOP
|
||||
*/
|
||||
|
||||
Generated
+9
-6
@@ -387,9 +387,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
|
||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
@@ -1163,9 +1166,9 @@
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
|
||||
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
|
||||
},
|
||||
"mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
|
||||
Generated
+166
-70
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.57.5",
|
||||
"version": "0.58.3-beta",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "trilium",
|
||||
"version": "0.57.5",
|
||||
"version": "0.58.3-beta",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@electron/remote": "2.0.9",
|
||||
"@excalidraw/excalidraw": "0.13.0",
|
||||
"archiver": "5.3.1",
|
||||
"async-mutex": "0.4.0",
|
||||
"axios": "1.2.1",
|
||||
"axios": "1.2.2",
|
||||
"better-sqlite3": "7.4.5",
|
||||
"chokidar": "3.5.3",
|
||||
"cls-hooked": "4.2.2",
|
||||
@@ -115,6 +115,11 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@braintree/sanitize-url": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz",
|
||||
"integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg=="
|
||||
},
|
||||
"node_modules/@develar/schema-utils": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
|
||||
@@ -807,6 +812,64 @@
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
|
||||
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdoc/salty": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
|
||||
@@ -1877,9 +1940,9 @@
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
|
||||
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
|
||||
"integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
@@ -6617,9 +6680,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
|
||||
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -6652,17 +6715,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"engines": [
|
||||
"node >=0.6.0"
|
||||
],
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
|
||||
"dependencies": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"json-schema": "0.4.0",
|
||||
"verror": "1.10.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/junk": {
|
||||
@@ -7315,9 +7378,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.1.30",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==",
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
|
||||
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
@@ -8487,9 +8550,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/request/node_modules/qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"version": "6.5.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
|
||||
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
@@ -9603,13 +9666,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
|
||||
"integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
|
||||
"version": "5.16.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
|
||||
"integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.7.2",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"bin": {
|
||||
@@ -9617,14 +9681,6 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"acorn": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
@@ -9667,15 +9723,6 @@
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/terser/node_modules/source-map": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/timm": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
|
||||
@@ -10552,6 +10599,11 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@braintree/sanitize-url": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz",
|
||||
"integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg=="
|
||||
},
|
||||
"@develar/schema-utils": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
|
||||
@@ -11081,6 +11133,55 @@
|
||||
"regenerator-runtime": "^0.13.3"
|
||||
}
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
|
||||
"integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"@jridgewell/resolve-uri": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
|
||||
"integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/set-array": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/source-map": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
|
||||
"integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
}
|
||||
},
|
||||
"@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.17",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
|
||||
"integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "1.4.14"
|
||||
}
|
||||
},
|
||||
"@jsdoc/salty": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.1.tgz",
|
||||
@@ -11984,9 +12085,9 @@
|
||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.1.tgz",
|
||||
"integrity": "sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
|
||||
"integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.15.0",
|
||||
"form-data": "^4.0.0",
|
||||
@@ -15619,9 +15720,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
|
||||
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
@@ -15648,13 +15749,13 @@
|
||||
}
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
"json-schema": "0.2.3",
|
||||
"json-schema": "0.4.0",
|
||||
"verror": "1.10.0"
|
||||
}
|
||||
},
|
||||
@@ -16167,9 +16268,9 @@
|
||||
}
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.30",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
|
||||
"integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
|
||||
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw=="
|
||||
},
|
||||
"napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
@@ -17082,9 +17183,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
"version": "6.5.3",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
|
||||
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.5.0",
|
||||
@@ -17946,13 +18047,14 @@
|
||||
}
|
||||
},
|
||||
"terser": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
|
||||
"integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
|
||||
"version": "5.16.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
|
||||
"integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map": "~0.7.2",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -17961,12 +18063,6 @@
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+11
-8
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.58.0-beta",
|
||||
"version": "0.58.4",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -13,12 +13,14 @@
|
||||
"url": "https://github.com/zadam/trilium.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev node ./src/www",
|
||||
"start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev electron --inspect=5858 .",
|
||||
"switch-server": "rm -r ./node_modules/better-sqlite3 && npm install",
|
||||
"switch-electron": "rm -r ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild",
|
||||
"build-backend-docs": "rm -r ./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 -r ./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/collapsible_widget.js",
|
||||
"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-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",
|
||||
"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/collapsible_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",
|
||||
"test-jasmine": "jasmine",
|
||||
@@ -27,11 +29,12 @@
|
||||
"postinstall": "rimraf ./node_modules/canvas"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@electron/remote": "2.0.9",
|
||||
"@excalidraw/excalidraw": "0.13.0",
|
||||
"archiver": "5.3.1",
|
||||
"async-mutex": "0.4.0",
|
||||
"axios": "1.2.1",
|
||||
"axios": "1.2.2",
|
||||
"better-sqlite3": "7.4.5",
|
||||
"chokidar": "3.5.3",
|
||||
"cls-hooked": "4.2.2",
|
||||
|
||||
@@ -13,7 +13,7 @@ describe("Search", () => {
|
||||
becca.reset();
|
||||
|
||||
rootNote = new NoteBuilder(new Note({noteId: 'root', title: 'root', type: 'text'}));
|
||||
new Branch({branchId: 'root', noteId: 'root', parentNoteId: 'none', notePosition: 10});
|
||||
new Branch({branchId: 'none_root', noteId: 'root', parentNoteId: 'none', notePosition: 10});
|
||||
});
|
||||
|
||||
it("simple path match", () => {
|
||||
|
||||
@@ -180,7 +180,7 @@ function getNotePath(noteId) {
|
||||
let branchId;
|
||||
|
||||
if (note.isRoot()) {
|
||||
branchId = 'root';
|
||||
branchId = 'none_root';
|
||||
}
|
||||
else {
|
||||
const parentNote = note.parents[0];
|
||||
|
||||
@@ -46,7 +46,10 @@ class AbstractEntity {
|
||||
return this.utcDateModified || this.utcDateCreated;
|
||||
}
|
||||
|
||||
/** @protected */
|
||||
/**
|
||||
* @protected
|
||||
* @returns {Becca}
|
||||
*/
|
||||
get becca() {
|
||||
if (!becca) {
|
||||
becca = require('../becca');
|
||||
@@ -75,7 +78,7 @@ class AbstractEntity {
|
||||
/**
|
||||
* Saves entity - executes SQL, but doesn't commit the transaction on its own
|
||||
*
|
||||
* @returns {AbstractEntity}
|
||||
* @returns {this}
|
||||
*/
|
||||
save() {
|
||||
const entityName = this.constructor.entityName;
|
||||
|
||||
@@ -78,7 +78,7 @@ class Branch extends AbstractEntity {
|
||||
childNote.parentBranches.push(this);
|
||||
}
|
||||
|
||||
if (this.branchId === 'root') {
|
||||
if (this.noteId === 'root') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,8 +165,7 @@ class Branch extends AbstractEntity {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.branchId === 'root'
|
||||
|| this.noteId === 'root'
|
||||
if (this.noteId === 'root'
|
||||
|| this.noteId === cls.getHoistedNoteId()) {
|
||||
|
||||
throw new Error("Can't delete root or hoisted branch/note");
|
||||
@@ -209,11 +208,19 @@ class Branch extends AbstractEntity {
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
if (!this.noteId || !this.parentNoteId) {
|
||||
throw new Error(`noteId and parentNoteId are mandatory properties for Branch`);
|
||||
}
|
||||
|
||||
this.branchId = `${this.parentNoteId}_${this.noteId}`;
|
||||
|
||||
if (this.notePosition === undefined || this.notePosition === null) {
|
||||
let maxNotePos = 0;
|
||||
|
||||
for (const childBranch of this.parentNote.getChildBranches()) {
|
||||
if (maxNotePos < childBranch.notePosition && childBranch.noteId !== '_hidden') {
|
||||
if (maxNotePos < childBranch.notePosition
|
||||
&& childBranch.noteId !== '_hidden' // hidden has very large notePosition to always stay last
|
||||
) {
|
||||
maxNotePos = childBranch.notePosition;
|
||||
}
|
||||
}
|
||||
@@ -225,6 +232,10 @@ class Branch extends AbstractEntity {
|
||||
this.isExpanded = false;
|
||||
}
|
||||
|
||||
if (!this.prefix?.trim()) {
|
||||
this.prefix = null;
|
||||
}
|
||||
|
||||
this.utcDateModified = dateUtils.utcNowDateTime();
|
||||
|
||||
super.beforeSaving();
|
||||
@@ -246,13 +257,20 @@ class Branch extends AbstractEntity {
|
||||
}
|
||||
|
||||
createClone(parentNoteId, notePosition) {
|
||||
return new Branch({
|
||||
noteId: this.noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
notePosition: notePosition,
|
||||
prefix: this.prefix,
|
||||
isExpanded: this.isExpanded
|
||||
});
|
||||
const existingBranch = this.becca.getBranchFromChildAndParent(this.noteId, parentNoteId);
|
||||
|
||||
if (existingBranch) {
|
||||
existingBranch.notePosition = notePosition;
|
||||
return existingBranch;
|
||||
} else {
|
||||
return new Branch({
|
||||
noteId: this.noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
notePosition: notePosition,
|
||||
prefix: this.prefix,
|
||||
isExpanded: this.isExpanded
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -945,13 +945,14 @@ class Note extends AbstractEntity {
|
||||
};
|
||||
}
|
||||
|
||||
/** @returns {String[]} */
|
||||
getSubtreeNoteIds({includeArchived = true, resolveSearch = false} = {}) {
|
||||
return this.getSubtree({includeArchived, resolveSearch})
|
||||
/** @returns {String[]} - includes the subtree node as well */
|
||||
getSubtreeNoteIds({includeArchived = true, includeHidden = false, resolveSearch = false} = {}) {
|
||||
return this.getSubtree({includeArchived, includeHidden, resolveSearch})
|
||||
.notes
|
||||
.map(note => note.noteId);
|
||||
}
|
||||
|
||||
/** @deprecated use getSubtreeNoteIds() instead */
|
||||
getDescendantNoteIds() {
|
||||
return this.getSubtreeNoteIds();
|
||||
}
|
||||
@@ -1171,7 +1172,8 @@ class Note extends AbstractEntity {
|
||||
* @param {string} type - attribute type (label / relation)
|
||||
* @param {string} name - name of the attribute, not including the leading ~/#
|
||||
* @param {string} [value] - value of the attribute - text for labels, target note ID for relations; optional.
|
||||
*
|
||||
* @param {boolean} [isInheritable=false]
|
||||
* @param {int} [position]
|
||||
* @return {Attribute}
|
||||
*/
|
||||
addAttribute(type, name, value = "", isInheritable = false, position = 1000) {
|
||||
@@ -1192,7 +1194,7 @@ class Note extends AbstractEntity {
|
||||
*
|
||||
* @param {string} name - name of the label, not including the leading #
|
||||
* @param {string} [value] - text value of the label; optional
|
||||
*
|
||||
* @param {boolean} [isInheritable=false]
|
||||
* @return {Attribute}
|
||||
*/
|
||||
addLabel(name, value = "", isInheritable = false) {
|
||||
@@ -1204,8 +1206,8 @@ class Note extends AbstractEntity {
|
||||
* returned.
|
||||
*
|
||||
* @param {string} name - name of the relation, not including the leading ~
|
||||
* @param {string} value - ID of the target note of the relation
|
||||
*
|
||||
* @param {string} targetNoteId
|
||||
* @param {boolean} [isInheritable=false]
|
||||
* @return {Attribute}
|
||||
*/
|
||||
addRelation(name, targetNoteId, isInheritable = false) {
|
||||
|
||||
@@ -35,15 +35,14 @@ function register(router) {
|
||||
existing.save();
|
||||
|
||||
return res.status(200).json(mappers.mapBranchToPojo(existing));
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const branch = new Branch(params).save();
|
||||
|
||||
try {
|
||||
const branch = new Branch(params).save();
|
||||
|
||||
res.status(201).json(mappers.mapBranchToPojo(branch));
|
||||
}
|
||||
catch (e) {
|
||||
throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message);
|
||||
res.status(201).json(mappers.mapBranchToPojo(branch));
|
||||
} catch (e) {
|
||||
throw new eu.EtapiError(400, eu.GENERIC_CODE, e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -291,6 +291,33 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/notes/{noteId}/note-revision:
|
||||
parameters:
|
||||
- name: noteId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/components/schemas/EntityId'
|
||||
- name: format
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
enum:
|
||||
- html
|
||||
- markdown
|
||||
default: html
|
||||
post:
|
||||
description: Create a note revision for the given note
|
||||
operationId: createNoteRevision
|
||||
responses:
|
||||
'204':
|
||||
description: revision has been created
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
/branches/{branchId}:
|
||||
parameters:
|
||||
- name: branchId
|
||||
|
||||
+19
-8
@@ -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 noteRevisionService = require("../services/note_revisions.js");
|
||||
|
||||
function register(router) {
|
||||
eu.route(router, 'get', '/etapi/notes', (req, res, next) => {
|
||||
@@ -122,6 +123,8 @@ function register(router) {
|
||||
|
||||
note.setContent(req.body);
|
||||
|
||||
noteService.scanForLinks(note);
|
||||
|
||||
return res.sendStatus(204);
|
||||
});
|
||||
|
||||
@@ -143,18 +146,26 @@ function register(router) {
|
||||
|
||||
zipExportService.exportToZip(taskContext, branch, format, res);
|
||||
});
|
||||
|
||||
eu.route(router, 'post' ,'/etapi/notes/:noteId/note-revision', (req, res, next) => {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
|
||||
note.saveNoteRevision();
|
||||
|
||||
return res.sendStatus(204);
|
||||
});
|
||||
}
|
||||
|
||||
function parseSearchParams(req) {
|
||||
const rawSearchParams = {
|
||||
'fastSearch': parseBoolean(req.query, 'fastSearch'),
|
||||
'includeArchivedNotes': parseBoolean(req.query, 'includeArchivedNotes'),
|
||||
'ancestorNoteId': req.query['ancestorNoteId'],
|
||||
'ancestorDepth': parseInteger(req.query, 'ancestorDepth'),
|
||||
'orderBy': req.query['orderBy'],
|
||||
'orderDirection': parseOrderDirection(req.query, 'orderDirection'),
|
||||
'limit': parseInteger(req.query, 'limit'),
|
||||
'debug': parseBoolean(req.query, 'debug')
|
||||
fastSearch: parseBoolean(req.query, 'fastSearch'),
|
||||
includeArchivedNotes: parseBoolean(req.query, 'includeArchivedNotes'),
|
||||
ancestorNoteId: req.query['ancestorNoteId'],
|
||||
ancestorDepth: req.query['ancestorDepth'], // e.g. "eq5"
|
||||
orderBy: req.query['orderBy'],
|
||||
orderDirection: parseOrderDirection(req.query, 'orderDirection'),
|
||||
limit: parseInteger(req.query, 'limit'),
|
||||
debug: parseBoolean(req.query, 'debug')
|
||||
};
|
||||
|
||||
const searchParams = {};
|
||||
|
||||
@@ -16,7 +16,7 @@ function isString(obj) {
|
||||
if (obj === undefined || obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (typeof obj !== 'string') {
|
||||
return `'${obj}' is not a string`;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ function isBoolean(obj) {
|
||||
if (obj === undefined || obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (typeof obj !== 'boolean') {
|
||||
return `'${obj}' is not a boolean`;
|
||||
}
|
||||
@@ -36,7 +36,7 @@ function isInteger(obj) {
|
||||
if (obj === undefined || obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!Number.isInteger(obj)) {
|
||||
return `'${obj}' is not an integer`;
|
||||
}
|
||||
@@ -46,13 +46,13 @@ function isNoteId(obj) {
|
||||
if (obj === undefined || obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const becca = require('../becca/becca');
|
||||
|
||||
|
||||
if (typeof obj !== 'string') {
|
||||
return `'${obj}' is not a valid noteId`;
|
||||
}
|
||||
|
||||
|
||||
if (!(obj in becca.notes)) {
|
||||
return `Note '${obj}' does not exist`;
|
||||
}
|
||||
@@ -84,8 +84,8 @@ function isValidEntityId(obj) {
|
||||
if (obj === undefined || obj === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof obj !== 'string' || !/^[A-Za-z0-9]{4,32}$/.test(obj)) {
|
||||
|
||||
if (typeof obj !== 'string' || !/^[A-Za-z0-9_]{4,128}$/.test(obj)) {
|
||||
return `'${obj}' is not a valid entityId. Only alphanumeric characters are allowed of length 4 to 32.`;
|
||||
}
|
||||
}
|
||||
@@ -100,4 +100,4 @@ module.exports = {
|
||||
isNoteType,
|
||||
isAttributeType,
|
||||
isValidEntityId
|
||||
};
|
||||
};
|
||||
|
||||
@@ -477,13 +477,13 @@ export default class TabManager extends Component {
|
||||
this.openAndActivateEmptyTab();
|
||||
}
|
||||
|
||||
async removeAllTabsCommand() {
|
||||
async closeAllTabsCommand() {
|
||||
for (const ntxIdToRemove of this.mainNoteContexts.map(nc => nc.ntxId)) {
|
||||
await this.removeNoteContext(ntxIdToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
async removeAllTabsExceptForThisCommand({ntxId}) {
|
||||
async closeOtherTabsCommand({ntxId}) {
|
||||
for (const ntxIdToRemove of this.mainNoteContexts.map(nc => nc.ntxId)) {
|
||||
if (ntxIdToRemove !== ntxId) {
|
||||
await this.removeNoteContext(ntxIdToRemove);
|
||||
@@ -491,6 +491,10 @@ export default class TabManager extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async closeTabCommand({ntxId}) {
|
||||
await this.removeNoteContext(ntxId);
|
||||
}
|
||||
|
||||
async moveTabToNewWindowCommand({ntxId}) {
|
||||
const {notePath, hoistedNoteId} = this.getNoteContextById(ntxId);
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
<h4>Example script</h4>
|
||||
|
||||
<pre>
|
||||
alert("Current note is " + api.getActiveContextNote().title);
|
||||
api.showMessage("Current note is " + api.getActiveContextNote().title);
|
||||
</pre>
|
||||
|
||||
@@ -32,7 +32,7 @@ export default class TreeContextMenu {
|
||||
const isHoisted = note.noteId === appContext.tabManager.getActiveContext().hoistedNoteId;
|
||||
const parentNote = isNotRoot ? await froca.getNote(branch.parentNoteId) : null;
|
||||
|
||||
// some actions don't support multi-note so they are disabled when notes are selected
|
||||
// some actions don't support multi-note, so they are disabled when notes are selected
|
||||
// the only exception is when the only selected note is the one that was right-clicked, then
|
||||
// it's clear what the user meant to do.
|
||||
const selNodes = this.treeWidget.getSelectedNodes();
|
||||
|
||||
@@ -10,7 +10,9 @@ async function moveBeforeBranch(branchIdsToMove, beforeBranchId) {
|
||||
branchIdsToMove = filterRootNote(branchIdsToMove);
|
||||
branchIdsToMove = filterSearchBranches(branchIdsToMove);
|
||||
|
||||
if (['root', '_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(beforeBranchId)) {
|
||||
const beforeBranch = await froca.getBranch(beforeBranchId);
|
||||
|
||||
if (['root', '_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(beforeBranch.noteId)) {
|
||||
toastService.showError('Cannot move notes here.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ class Froca {
|
||||
getNotesFromCache(noteIds, silentNotFoundError = false) {
|
||||
return noteIds.map(noteId => {
|
||||
if (!this.notes[noteId] && !silentNotFoundError) {
|
||||
console.trace(`Can't find note "${noteId}"`);
|
||||
console.trace(`Can't find note '${noteId}'`);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -235,7 +235,7 @@ class Froca {
|
||||
|
||||
return noteIds.map(noteId => {
|
||||
if (!this.notes[noteId] && !silentNotFoundError) {
|
||||
console.trace(`Can't find note "${noteId}"`);
|
||||
console.trace(`Can't find note '${noteId}'`);
|
||||
|
||||
return null;
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ class Froca {
|
||||
getBranch(branchId, silentNotFoundError = false) {
|
||||
if (!(branchId in this.branches)) {
|
||||
if (!silentNotFoundError) {
|
||||
logError(`Not existing branch ${branchId}`);
|
||||
logError(`Not existing branch '${branchId}'`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -295,13 +295,13 @@ class Froca {
|
||||
|
||||
async getBranchId(parentNoteId, childNoteId) {
|
||||
if (childNoteId === 'root') {
|
||||
return 'root';
|
||||
return 'none_root';
|
||||
}
|
||||
|
||||
const child = await this.getNote(childNoteId);
|
||||
|
||||
if (!child) {
|
||||
logError(`Could not find branchId for parent=${parentNoteId}, child=${childNoteId} since child does not exist`);
|
||||
logError(`Could not find branchId for parent '${parentNoteId}', child '${childNoteId}' since child does not exist`);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -318,9 +318,9 @@ class Froca {
|
||||
.then(row => new NoteComplement(row))
|
||||
.catch(e => console.error(`Cannot get note complement for note '${noteId}'`));
|
||||
|
||||
// we don't want to keep large payloads forever in memory so we clean that up quite quickly
|
||||
// we don't want to keep large payloads forever in memory, so we clean that up quite quickly
|
||||
// this cache is more meant to share the data between different components within one business transaction (e.g. loading of the note into the tab context and all the components)
|
||||
// this is also a work around for missing invalidation after change
|
||||
// this is also a workaround for missing invalidation after change
|
||||
this.noteComplementPromises[noteId].then(
|
||||
() => setTimeout(() => this.noteComplementPromises[noteId] = null, 1000)
|
||||
);
|
||||
|
||||
@@ -41,6 +41,24 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
|
||||
/** @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;
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import openService from "./open.js";
|
||||
import froca from "./froca.js";
|
||||
import utils from "./utils.js";
|
||||
import linkService from "./link.js";
|
||||
import treeService from "./tree.js";
|
||||
|
||||
let idCounter = 1;
|
||||
|
||||
@@ -31,6 +32,17 @@ async function getRenderedContent(note, options = {}) {
|
||||
|
||||
renderMathInElement($renderedContent[0], {trust: true});
|
||||
}
|
||||
|
||||
const getNoteIdFromLink = el => treeService.getNoteIdFromNotePath($(el).attr('href'));
|
||||
const referenceLinks = $renderedContent.find("a.reference-link");
|
||||
const noteIdsToPrefetch = referenceLinks.map(el => getNoteIdFromLink(el));
|
||||
await froca.getNotes(noteIdsToPrefetch);
|
||||
|
||||
for (const el of referenceLinks) {
|
||||
const noteId = getNoteIdFromLink(el);
|
||||
|
||||
await linkService.loadReferenceLinkTitle(noteId, $(el));
|
||||
}
|
||||
}
|
||||
else {
|
||||
await renderChildrenList($renderedContent, note);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||
|
||||
const TPL = `<button class="button-widget no-print" data-toggle="tooltip">
|
||||
<span class="bx"></span>
|
||||
</button>`;
|
||||
const TPL = `<button class="button-widget bx"
|
||||
data-toggle="tooltip"
|
||||
title=""></button>`;
|
||||
|
||||
export default class AbstractButtonWidget extends NoteContextAwareWidget {
|
||||
isEnabled() {
|
||||
@@ -22,13 +22,14 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget {
|
||||
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$iconSpan = this.$widget.find("span");
|
||||
|
||||
if (this.settings.onContextMenu) {
|
||||
this.$widget.on("contextmenu", e => {
|
||||
this.$widget.tooltip("hide");
|
||||
|
||||
this.settings.onContextMenu(e);
|
||||
|
||||
return false; // blocks default browser right click menu
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,9 +51,9 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget {
|
||||
}
|
||||
|
||||
refreshIcon() {
|
||||
for (const className of this.$iconSpan[0].classList) {
|
||||
for (const className of this.$widget[0].classList) {
|
||||
if (className.startsWith("bx-")) {
|
||||
this.$iconSpan.removeClass(className);
|
||||
this.$widget.removeClass(className);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ export default class AbstractButtonWidget extends NoteContextAwareWidget {
|
||||
? this.settings.icon()
|
||||
: this.settings.icon;
|
||||
|
||||
this.$iconSpan.addClass(icon);
|
||||
this.$widget.addClass(icon);
|
||||
}
|
||||
|
||||
initialRenderCompleteEvent() {
|
||||
|
||||
@@ -39,12 +39,10 @@ export default class EditButton extends OnClickButtonWidget {
|
||||
// make the edit button stand out on the first display, otherwise
|
||||
// it's difficult to notice that the note is readonly
|
||||
if (this.isVisible() && !wasVisible) {
|
||||
this.$iconSpan.addClass("bx-tada");
|
||||
this.$widget.css("transform", "scale(2)");
|
||||
this.$widget.addClass("bx-tada bx-lg");
|
||||
|
||||
setTimeout(() => {
|
||||
this.$iconSpan.removeClass("bx-tada bx-lg");
|
||||
this.$widget.css("transform", "scale(1)");
|
||||
this.$widget.removeClass("bx-tada bx-lg");
|
||||
}, 1700);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ const TPL = `
|
||||
background-position: 50% 45%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.global-menu-button:hover {
|
||||
background-image: url("${window.glob.assetPath}/images/icon-color.png");
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.global-menu-button-update-available {
|
||||
@@ -80,7 +80,7 @@ const TPL = `
|
||||
display: none;
|
||||
}
|
||||
|
||||
body.mobile .dropdown-submenu .dropdown-menu {
|
||||
body.mobile .global-menu .dropdown-submenu .dropdown-menu {
|
||||
display: block;
|
||||
font-size: 90%;
|
||||
position: relative;
|
||||
|
||||
@@ -36,7 +36,9 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
|
||||
|
||||
// API is broken and will be replaced: https://github.com/electron/electron/issues/33899
|
||||
// until then no context menu
|
||||
return;
|
||||
if (true) { // avoid warning in dev console
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.webContents.history.length < 2) {
|
||||
return;
|
||||
|
||||
@@ -320,8 +320,6 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
||||
&& attributeService.isAffecting(attr, this.note));
|
||||
|
||||
if (label || relation) {
|
||||
console.log("OOOO");
|
||||
|
||||
// probably incorrect event
|
||||
// calling this.refresh() is not enough since the event needs to be propagated to children as well
|
||||
this.triggerEvent('noteTypeMimeChanged', {noteId: this.noteId});
|
||||
|
||||
@@ -5,6 +5,9 @@ import hoistedNoteService from "../services/hoisted_note.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||
import linkContextMenuService from "../menus/link_context_menu.js";
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const esc = utils.escapeHtml;
|
||||
|
||||
const TPL = `<div class="note-map-widget" style="position: relative;">
|
||||
<style>
|
||||
@@ -102,7 +105,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
||||
ctx.arc(node.x, node.y, this.noteIdToSizeMap[node.id], 0, 2 * Math.PI, false);
|
||||
ctx.fill();
|
||||
})
|
||||
.nodeLabel(node => node.name)
|
||||
.nodeLabel(node => esc(node.name))
|
||||
.maxZoom(7)
|
||||
.warmupTicks(30)
|
||||
.linkDirectionalArrowLength(5)
|
||||
@@ -114,7 +117,7 @@ export default class NoteMapWidget extends NoteContextAwareWidget {
|
||||
|
||||
if (this.mapType === 'link') {
|
||||
this.graph
|
||||
.linkLabel(l => `${l.source.name} - <strong>${l.name}</strong> - ${l.target.name}`)
|
||||
.linkLabel(l => `${esc(l.source.name)} - <strong>${esc(l.name)}</strong> - ${esc(l.target.name)}`)
|
||||
.linkCanvasObject((link, ctx) => this.paintLink(link, ctx))
|
||||
.linkCanvasObjectMode(() => "after");
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
||||
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
||||
|
||||
const importService = await import('../services/import');
|
||||
const importService = await import('../services/import.js');
|
||||
|
||||
importService.uploadFiles(node.data.noteId, files, {
|
||||
safeImport: true,
|
||||
@@ -637,7 +637,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
}
|
||||
|
||||
prepareRootNode() {
|
||||
return this.prepareNode(froca.getBranch('root'));
|
||||
return this.prepareNode(froca.getBranch('none_root'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1606,7 +1606,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
const resp = await server.post(`special-notes/launchers/${node.data.noteId}/${launcherType}`);
|
||||
|
||||
if (!resp.success) {
|
||||
alert(resp.message);
|
||||
toastService.showError(resp.message);
|
||||
}
|
||||
|
||||
await ws.waitForMaxKnownEntityChangeId();
|
||||
|
||||
@@ -31,6 +31,8 @@ export default class SpacerWidget extends BasicWidget {
|
||||
appContext.triggerCommand(command);
|
||||
}
|
||||
});
|
||||
|
||||
return false; // blocks default browser right click menu
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,9 +262,10 @@ export default class TabRowWidget extends BasicWidget {
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "bx bx-window-open"},
|
||||
{title: "Close all tabs", command: "removeAllTabs", uiIcon: "bx bx-x"},
|
||||
{title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "bx bx-x"},
|
||||
{title: "Close", command: "closeTab", uiIcon: "bx bx-x"},
|
||||
{title: "Close other tabs", command: "closeOtherTabs", uiIcon: "bx bx-x"},
|
||||
{title: "Close all tabs", command: "closeAllTabs", uiIcon: "bx bx-x"},
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "bx bx-window-open"}
|
||||
],
|
||||
selectMenuItemHandler: ({command}) => {
|
||||
this.triggerCommand(command, {ntxId});
|
||||
|
||||
@@ -126,7 +126,7 @@ export default class TocWidget extends CollapsibleWidget {
|
||||
getToc(html) {
|
||||
// Regular expression for headings <h1>...</h1> using non-greedy
|
||||
// matching and backreferences
|
||||
const headingTagsRegex = /<h(\d+)>(.*?)<\/h\1>/g;
|
||||
const headingTagsRegex = /<h(\d+)[^>]*>(.*?)<\/h\1>/gi;
|
||||
|
||||
// Use jquery to build the table rather than html text, since it makes
|
||||
// it easier to set the onclick event that will be executed with the
|
||||
@@ -151,7 +151,8 @@ export default class TocWidget extends CollapsibleWidget {
|
||||
}
|
||||
} else if (levelDelta < 0) {
|
||||
// Close as many lists as curLevel - newLevel
|
||||
for (let i = 0; i < -levelDelta; ++i) {
|
||||
// be careful not to empty $ols completely, the root element should stay (could happen with a rogue h1 element)
|
||||
for (let i = 0; i < -levelDelta && $ols.length > 1; ++i) {
|
||||
$ols.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export default class DocTypeWidget extends TypeWidget {
|
||||
const docName = note.getLabelValue('docName');
|
||||
|
||||
if (docName) {
|
||||
this.$content.load(`${window.glob.assetPath}/app/doc_notes/${docName}.html`);
|
||||
this.$content.load(`${window.glob.appPath}/doc_notes/${docName}.html`);
|
||||
} else {
|
||||
this.$content.empty();
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
this.watchdog.editor.model.document.on('change:data', () => this.spacedUpdate.scheduleUpdate());
|
||||
|
||||
if (glob.isDev && ENABLE_INSPECTOR) {
|
||||
await import(/* webpackIgnore: true */'../../../libraries/ckeditor/inspector');
|
||||
await import(/* webpackIgnore: true */'../../../libraries/ckeditor/inspector.js');
|
||||
CKEditorInspector.attach(this.watchdog.editor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ export default class RelationMapTypeWidget extends TypeWidget {
|
||||
selectMenuItemHandler: ({command}) => this.contextMenuHandler(command, e.target)
|
||||
});
|
||||
|
||||
return false;
|
||||
return false; // blocks default browser right click menu
|
||||
});
|
||||
|
||||
this.clipboard = null;
|
||||
|
||||
@@ -987,3 +987,7 @@ button.close:hover {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,6 @@ function updateNoteAttribute(req) {
|
||||
attribute.markAsDeleted();
|
||||
}
|
||||
|
||||
console.log(attribute);
|
||||
|
||||
attribute.save();
|
||||
|
||||
return {
|
||||
@@ -172,7 +170,7 @@ function updateNoteAttributes(req) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// no existing attribute has been matched so we need to create a new one
|
||||
// no existing attribute has been matched, so we need to create a new one
|
||||
// type, name and isInheritable are immutable so even if there is an attribute with matching type & name, we need to create a new one and delete the former one
|
||||
|
||||
note.addAttribute(incAttr.type, incAttr.name, incAttr.value, incAttr.isInheritable, position);
|
||||
|
||||
@@ -143,7 +143,7 @@ function setExpanded(req) {
|
||||
const {branchId} = req.params;
|
||||
const expanded = parseInt(req.params.expanded);
|
||||
|
||||
if (branchId !== 'root') {
|
||||
if (branchId !== 'none_root') {
|
||||
sql.execute("UPDATE branches SET isExpanded = ? WHERE branchId = ?", [expanded, branchId]);
|
||||
// we don't sync expanded label
|
||||
// also this does not trigger updates to the frontend, this would trigger too many reloads
|
||||
@@ -172,7 +172,7 @@ function setExpandedForSubtree(req) {
|
||||
SELECT branchId FROM tree`, [branchId]);
|
||||
|
||||
// root is always expanded
|
||||
branchIds = branchIds.filter(branchId => branchId !== 'root');
|
||||
branchIds = branchIds.filter(branchId => branchId !== 'none_root');
|
||||
|
||||
sql.executeMany(`UPDATE branches SET isExpanded = ${expanded} WHERE branchId IN (???)`, branchIds);
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ const Attribute = require('../../becca/entities/attribute');
|
||||
const htmlSanitizer = require('../../services/html_sanitizer');
|
||||
const {formatAttrForSearch} = require("../../services/attribute_formatter");
|
||||
|
||||
function findClippingNote(todayNote, pageUrl) {
|
||||
const notes = todayNote.searchNotesInSubtree(
|
||||
function findClippingNote(clipperInboxNote, pageUrl) {
|
||||
const notes = clipperInboxNote.searchNotesInSubtree(
|
||||
formatAttrForSearch({
|
||||
type: 'label',
|
||||
name: "pageUrl",
|
||||
@@ -47,6 +47,7 @@ function addClipping(req) {
|
||||
|
||||
const clipperInbox = getClipperInboxNote();
|
||||
|
||||
pageUrl = htmlSanitizer.sanitizeUrl(pageUrl);
|
||||
let clippingNote = findClippingNote(clipperInbox, pageUrl);
|
||||
|
||||
if (!clippingNote) {
|
||||
@@ -57,8 +58,6 @@ function addClipping(req) {
|
||||
type: 'text'
|
||||
}).note;
|
||||
|
||||
pageUrl = htmlSanitizer.sanitize(pageUrl);
|
||||
|
||||
clippingNote.setLabel('clipType', 'clippings');
|
||||
clippingNote.setLabel('pageUrl', pageUrl);
|
||||
clippingNote.setLabel('iconClass', 'bx bx-globe');
|
||||
@@ -96,7 +95,7 @@ function createNote(req) {
|
||||
note.setLabel('clipType', clipType);
|
||||
|
||||
if (pageUrl) {
|
||||
pageUrl = htmlSanitizer.sanitize(pageUrl);
|
||||
pageUrl = htmlSanitizer.sanitizeUrl(pageUrl);
|
||||
|
||||
note.setLabel('pageUrl', pageUrl);
|
||||
note.setLabel('iconClass', 'bx bx-globe');
|
||||
|
||||
@@ -13,7 +13,7 @@ function exportBranch(req, res) {
|
||||
const branch = becca.getBranch(branchId);
|
||||
|
||||
if (!branch) {
|
||||
const message = `Cannot export branch ${branchId} since it does not exist.`;
|
||||
const message = `Cannot export branch '${branchId}' since it does not exist.`;
|
||||
log.error(message);
|
||||
|
||||
res.setHeader("Content-Type", "text/plain")
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
|
||||
const imageType = require('image-type');
|
||||
const imageService = require('../../services/image');
|
||||
const dateNoteService = require('../../services/date_notes');
|
||||
const noteService = require('../../services/notes');
|
||||
const attributeService = require('../../services/attributes');
|
||||
const {sanitizeAttributeName} = require("../../services/sanitize_attribute_name.js");
|
||||
const specialNotesService = require("../../services/special_notes.js");
|
||||
|
||||
function uploadImage(req) {
|
||||
const file = req.file;
|
||||
@@ -16,7 +15,7 @@ function uploadImage(req) {
|
||||
|
||||
const originalName = `Sender image.${imageType(file.buffer).ext}`;
|
||||
|
||||
const parentNote = dateNoteService.getDayNote(req.headers['x-local-date']);
|
||||
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
||||
|
||||
const {note, noteId} = imageService.saveImage(parentNote.noteId, file.buffer, originalName, true);
|
||||
|
||||
@@ -38,7 +37,7 @@ function uploadImage(req) {
|
||||
}
|
||||
|
||||
function saveNote(req) {
|
||||
const parentNote = dateNoteService.getDayNote(req.headers['x-local-date']);
|
||||
const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']);
|
||||
|
||||
const {note, branch} = noteService.createNewNote({
|
||||
parentNoteId: parentNote.noteId,
|
||||
|
||||
@@ -66,7 +66,7 @@ function getNotesAndBranchesAndAttributes(noteIds) {
|
||||
|
||||
if (noteIds.has('root')) {
|
||||
branches.push({
|
||||
branchId: 'root',
|
||||
branchId: 'none_root',
|
||||
noteId: 'root',
|
||||
parentNoteId: 'none',
|
||||
notePosition: 0,
|
||||
|
||||
+3
-1
@@ -10,6 +10,7 @@ const utils = require('../services/utils');
|
||||
const protectedSessionService = require("../services/protected_session");
|
||||
const packageJson = require('../../package.json');
|
||||
const assetPath = require("../services/asset_path");
|
||||
const appPath = require("../services/app_path");
|
||||
|
||||
function index(req, res) {
|
||||
const options = optionService.getOptionsMap();
|
||||
@@ -38,7 +39,8 @@ function index(req, res) {
|
||||
isProtectedSessionAvailable: protectedSessionService.isProtectedSessionAvailable(),
|
||||
maxContentWidth: parseInt(options.maxContentWidth),
|
||||
triliumVersion: packageJson.version,
|
||||
assetPath: assetPath
|
||||
assetPath: assetPath,
|
||||
appPath: appPath
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -6,19 +6,22 @@ const myScryptService = require('../services/my_scrypt');
|
||||
const log = require('../services/log');
|
||||
const passwordService = require("../services/password");
|
||||
const assetPath = require("../services/asset_path");
|
||||
const appPath = require("../services/app_path");
|
||||
const ValidationError = require("../errors/validation_error");
|
||||
|
||||
function loginPage(req, res) {
|
||||
res.render('login', {
|
||||
failedAuth: false,
|
||||
assetPath: assetPath
|
||||
assetPath: assetPath,
|
||||
appPath: appPath
|
||||
});
|
||||
}
|
||||
|
||||
function setPasswordPage(req, res) {
|
||||
res.render('set_password', {
|
||||
error: false,
|
||||
assetPath: assetPath
|
||||
assetPath: assetPath,
|
||||
appPath: appPath
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -4,6 +4,7 @@ const sqlInit = require('../services/sql_init');
|
||||
const setupService = require('../services/setup');
|
||||
const utils = require('../services/utils');
|
||||
const assetPath = require("../services/asset_path");
|
||||
const appPath = require("../services/app_path.js");
|
||||
|
||||
function setupPage(req, res) {
|
||||
if (sqlInit.isDbInitialized()) {
|
||||
@@ -14,7 +15,7 @@ function setupPage(req, res) {
|
||||
windowService.closeSetupWindow();
|
||||
}
|
||||
else {
|
||||
res.redirect('/');
|
||||
res.redirect('.');
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -31,7 +32,8 @@ function setupPage(req, res) {
|
||||
|
||||
res.render('setup', {
|
||||
syncInProgress: syncInProgress,
|
||||
assetPath: assetPath
|
||||
assetPath: assetPath,
|
||||
appPath: appPath
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ const build = require('./build');
|
||||
const packageJson = require('../../package');
|
||||
const {TRILIUM_DATA_DIR} = require('./data_dir');
|
||||
|
||||
const APP_DB_VERSION = 209;
|
||||
const SYNC_VERSION = 28;
|
||||
const APP_DB_VERSION = 212;
|
||||
const SYNC_VERSION = 29;
|
||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
const assetPath = require("./asset_path");
|
||||
const env = require("./env");
|
||||
|
||||
module.exports = env.isDev()
|
||||
? assetPath + "/app"
|
||||
: assetPath + "/app-dist";
|
||||
@@ -392,10 +392,33 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @deprecated - use sortNotes instead
|
||||
* @param {string} parentNoteId - this note's child notes will be sorted
|
||||
*/
|
||||
this.sortNotesByTitle = parentNoteId => treeService.sortNotes(parentNoteId);
|
||||
|
||||
/**
|
||||
* @typedef {Object} SortConfig
|
||||
* @property {string} [sortBy=title] - 'title', 'dateCreated', 'dateModified' or a label name
|
||||
* see https://github.com/zadam/trilium/wiki/Sorting for details.
|
||||
* @property {boolean} [reverse=false]
|
||||
* @property {boolean} [foldersFirst=false]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sort child notes of a given note.
|
||||
*
|
||||
* @method
|
||||
* @param {string} parentNoteId - this note's child notes will be sorted
|
||||
* @param {SortConfig} [sortConfig]
|
||||
*/
|
||||
this.sortNotes = (parentNoteId, sortConfig = {}) => treeService.sortNotes(
|
||||
parentNoteId,
|
||||
sortConfig.sortBy || "title",
|
||||
!!sortConfig.reverse,
|
||||
!!sortConfig.foldersFirst
|
||||
);
|
||||
|
||||
/**
|
||||
* This method finds note by its noteId and prefix and either sets it to the given parentNoteId
|
||||
* or removes the branch (if parentNoteId is not given).
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2022-12-24T22:09:05+01:00", buildRevision: "f08fbf7bca60fc7c727d96b10785a0c5a5f93810" };
|
||||
module.exports = { buildDate:"2023-01-11T23:44:33+01:00", buildRevision: "bdfdc0402ddb23e9af002580f368bc52e4268b3a" };
|
||||
|
||||
@@ -35,7 +35,7 @@ function cloneNoteToNote(noteId, parentNoteId, prefix) {
|
||||
isExpanded: 0
|
||||
}).save();
|
||||
|
||||
log.info(`Cloned note ${noteId} to new parent note ${parentNoteId} with prefix ${prefix}`);
|
||||
log.info(`Cloned note '${noteId}' to new parent note '${parentNoteId}' with prefix '${prefix}'`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@@ -78,14 +78,14 @@ function ensureNoteIsPresentInParent(noteId, parentNoteId, prefix) {
|
||||
return validationResult;
|
||||
}
|
||||
|
||||
new Branch({
|
||||
const branch = new Branch({
|
||||
noteId: noteId,
|
||||
parentNoteId: parentNoteId,
|
||||
prefix: prefix,
|
||||
isExpanded: 0
|
||||
}).save();
|
||||
|
||||
log.info(`Ensured note '${noteId}' is in parent note '${parentNoteId}' with prefix '${prefix}'`);
|
||||
log.info(`Ensured note '${noteId}' is in parent note '${parentNoteId}' with prefix '${branch.prefix}'`);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
@@ -169,7 +169,7 @@ function cloneNoteAfter(noteId, afterBranchId) {
|
||||
isExpanded: 0
|
||||
}).save();
|
||||
|
||||
log.info(`Cloned note '${noteId}' into parent note '${afterNote.parentNoteId}' after note '${afterNote.noteId}', branch ${afterBranchId}`);
|
||||
log.info(`Cloned note '${noteId}' into parent note '${afterNote.parentNoteId}' after note '${afterNote.noteId}', branch '${afterBranchId}'`);
|
||||
|
||||
return { success: true, branchId: branch.branchId };
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const Branch = require('../becca/entities/branch');
|
||||
const noteRevisionService = require('./note_revisions');
|
||||
const becca = require("../becca/becca");
|
||||
const utils = require("../services/utils");
|
||||
const {sanitizeAttributeName} = require("./sanitize_attribute_name.js");
|
||||
const {sanitizeAttributeName} = require("./sanitize_attribute_name");
|
||||
const noteTypes = require("../services/note_types").getNoteTypeNames();
|
||||
|
||||
class ConsistencyChecks {
|
||||
@@ -72,7 +72,7 @@ class ConsistencyChecks {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logError(`Tree cycle detected at parent-child relationship: ${parentNoteId} - ${noteId}, whole path: ${path}`);
|
||||
logError(`Tree cycle detected at parent-child relationship: '${parentNoteId}' - '${noteId}', whole path: '${path}'`);
|
||||
|
||||
this.unrecoveredConsistencyErrors = true;
|
||||
}
|
||||
@@ -133,9 +133,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Branch ${branchId} has been deleted since it references missing note ${noteId}`);
|
||||
logFix(`Branch '${branchId}' has been deleted since it references missing note '${noteId}'`);
|
||||
} else {
|
||||
logError(`Branch ${branchId} references missing note ${noteId}`);
|
||||
logError(`Branch '${branchId}' references missing note '${noteId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -144,7 +144,7 @@ class ConsistencyChecks {
|
||||
FROM branches
|
||||
LEFT JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
WHERE branches.isDeleted = 0
|
||||
AND branches.branchId != 'root'
|
||||
AND branches.noteId != 'root'
|
||||
AND notes.noteId IS NULL`,
|
||||
({branchId, parentNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
@@ -154,9 +154,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Branch ${branchId} was set to root parent since it was referencing missing parent note ${parentNoteId}`);
|
||||
logFix(`Branch '${branchId}' was set to root parent since it was referencing missing parent note '${parentNoteId}'`);
|
||||
} else {
|
||||
logError(`Branch ${branchId} references missing parent note ${parentNoteId}`);
|
||||
logError(`Branch '${branchId}' references missing parent note '${parentNoteId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -173,9 +173,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Attribute ${attributeId} has been deleted since it references missing source note ${noteId}`);
|
||||
logFix(`Attribute '${attributeId}' has been deleted since it references missing source note '${noteId}'`);
|
||||
} else {
|
||||
logError(`Attribute ${attributeId} references missing source note ${noteId}`);
|
||||
logError(`Attribute '${attributeId}' references missing source note '${noteId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -193,9 +193,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Relation ${attributeId} has been deleted since it references missing note ${noteId}`)
|
||||
logFix(`Relation '${attributeId}' has been deleted since it references missing note '${noteId}'`)
|
||||
} else {
|
||||
logError(`Relation ${attributeId} references missing note ${noteId}`)
|
||||
logError(`Relation '${attributeId}' references missing note '${noteId}'`)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -220,9 +220,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Branch ${branchId} has been deleted since associated note ${noteId} is deleted.`);
|
||||
logFix(`Branch '${branchId}' has been deleted since associated note '${noteId}' is deleted.`);
|
||||
} else {
|
||||
logError(`Branch ${branchId} is not deleted even though associated note ${noteId} is deleted.`)
|
||||
logError(`Branch '${branchId}' is not deleted even though associated note '${noteId}' is deleted.`)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -240,9 +240,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Branch ${branchId} has been deleted since associated parent note ${parentNoteId} is deleted.`);
|
||||
logFix(`Branch '${branchId}' has been deleted since associated parent note '${parentNoteId}' is deleted.`);
|
||||
} else {
|
||||
logError(`Branch ${branchId} is not deleted even though associated parent note ${parentNoteId} is deleted.`)
|
||||
logError(`Branch '${branchId}' is not deleted even though associated parent note '${parentNoteId}' is deleted.`)
|
||||
}
|
||||
});
|
||||
|
||||
@@ -262,9 +262,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Created missing branch ${branch.branchId} for note ${noteId}`);
|
||||
logFix(`Created missing branch '${branch.branchId}' for note '${noteId}'`);
|
||||
} else {
|
||||
logError(`No undeleted branch found for note ${noteId}`);
|
||||
logError(`No undeleted branch found for note '${noteId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -296,12 +296,12 @@ class ConsistencyChecks {
|
||||
for (const branch of branches.slice(1)) {
|
||||
branch.markAsDeleted();
|
||||
|
||||
logFix(`Removing branch ${branch.branchId} since it's parent-child duplicate of branch ${origBranch.branchId}`);
|
||||
logFix(`Removing branch '${branch.branchId}' since it's a parent-child duplicate of branch '${origBranch.branchId}'`);
|
||||
}
|
||||
|
||||
this.reloadNeeded = true;
|
||||
} else {
|
||||
logError(`Duplicate branches for note ${noteId} and parent ${parentNoteId}`);
|
||||
logError(`Duplicate branches for note '${noteId}' and parent '${parentNoteId}'`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -322,9 +322,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Note ${noteId} type has been change to file since it had invalid type=${type}`)
|
||||
logFix(`Note '${noteId}' type has been change to file since it had invalid type '${type}'`)
|
||||
} else {
|
||||
logError(`Note ${noteId} has invalid type=${type}`);
|
||||
logError(`Note '${noteId}' has invalid type '${type}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -361,9 +361,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Note ${noteId} content was set to empty string since there was no corresponding row`);
|
||||
logFix(`Note '${noteId}' content was set to empty string since there was no corresponding row`);
|
||||
} else {
|
||||
logError(`Note ${noteId} content row does not exist`);
|
||||
logError(`Note '${noteId}' content row does not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -385,9 +385,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Note ${noteId} content was set to "${blankContent}" since it was null even though it is not deleted`);
|
||||
logFix(`Note '${noteId}' content was set to '${blankContent}' since it was null even though it is not deleted`);
|
||||
} else {
|
||||
logError(`Note ${noteId} content is null even though it is not deleted`);
|
||||
logError(`Note '${noteId}' content is null even though it is not deleted`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -404,9 +404,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Note revision content ${noteRevisionId} was created and set to erased since it did not exist.`);
|
||||
logFix(`Note revision content '${noteRevisionId}' was created and set to erased since it did not exist.`);
|
||||
} else {
|
||||
logError(`Note revision content ${noteRevisionId} does not exist`);
|
||||
logError(`Note revision content '${noteRevisionId}' does not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -431,12 +431,12 @@ class ConsistencyChecks {
|
||||
branch.parentNoteId = 'root';
|
||||
branch.save();
|
||||
|
||||
logFix(`Child branch ${branch.branchId} has been moved to root since it was a child of a search note ${parentNoteId}`)
|
||||
logFix(`Child branch '${branch.branchId}' has been moved to root since it was a child of a search note '${parentNoteId}'`)
|
||||
}
|
||||
|
||||
this.reloadNeeded = true;
|
||||
} else {
|
||||
logError(`Search note ${parentNoteId} has children`);
|
||||
logError(`Search note '${parentNoteId}' has children`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -453,9 +453,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Removed relation ${relation.attributeId} of name "${relation.name} with empty target.`);
|
||||
logFix(`Removed relation '${relation.attributeId}' of name '${relation.name}' with empty target.`);
|
||||
} else {
|
||||
logError(`Relation ${attributeId} has empty target.`);
|
||||
logError(`Relation '${attributeId}' has empty target.`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -474,9 +474,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Attribute ${attributeId} type was changed to label since it had invalid type '${type}'`);
|
||||
logFix(`Attribute '${attributeId}' type was changed to label since it had invalid type '${type}'`);
|
||||
} else {
|
||||
logError(`Attribute ${attributeId} has invalid type '${type}'`);
|
||||
logError(`Attribute '${attributeId}' has invalid type '${type}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -494,9 +494,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Removed attribute ${attributeId} because owning note ${noteId} is also deleted.`);
|
||||
logFix(`Removed attribute '${attributeId}' because owning note '${noteId}' is also deleted.`);
|
||||
} else {
|
||||
logError(`Attribute ${attributeId} is not deleted even though owning note ${noteId} is deleted.`);
|
||||
logError(`Attribute '${attributeId}' is not deleted even though owning note '${noteId}' is deleted.`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -515,9 +515,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Removed attribute ${attributeId} because target note ${targetNoteId} is also deleted.`);
|
||||
logFix(`Removed attribute '${attributeId}' because target note '${targetNoteId}' is also deleted.`);
|
||||
} else {
|
||||
logError(`Attribute ${attributeId} is not deleted even though target note ${targetNoteId} is deleted.`);
|
||||
logError(`Attribute '${attributeId}' is not deleted even though target note '${targetNoteId}' is deleted.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -545,9 +545,9 @@ class ConsistencyChecks {
|
||||
isSynced: entityName !== 'options' || entity.isSynced
|
||||
});
|
||||
|
||||
logFix(`Created missing entity change for entityName=${entityName}, entityId=${entityId}`);
|
||||
logFix(`Created missing entity change for entityName '${entityName}', entityId '${entityId}'`);
|
||||
} else {
|
||||
logError(`Missing entity change for entityName=${entityName}, entityId=${entityId}`);
|
||||
logError(`Missing entity change for entityName '${entityName}', entityId '${entityId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -565,9 +565,9 @@ class ConsistencyChecks {
|
||||
if (this.autoFix) {
|
||||
sql.execute("DELETE FROM entity_changes WHERE entityName = ? AND entityId = ?", [entityName, entityId]);
|
||||
|
||||
logFix(`Deleted extra entity change id=${id}, entityName=${entityName}, entityId=${entityId}`);
|
||||
logFix(`Deleted extra entity change id '${id}', entityName '${entityName}', entityId '${entityId}'`);
|
||||
} else {
|
||||
logError(`Unrecognized entity change id=${id}, entityName=${entityName}, entityId=${entityId}`);
|
||||
logError(`Unrecognized entity change id '${id}', entityName '${entityName}', entityId '${entityId}'`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -586,9 +586,9 @@ class ConsistencyChecks {
|
||||
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Erasing entityName=${entityName}, entityId=${entityId} since entity change id=${id} has it as erased.`);
|
||||
logFix(`Erasing entityName '${entityName}', entityId '${entityId}' since entity change id '${id}' has it as erased.`);
|
||||
} else {
|
||||
logError(`Entity change id=${id} has entityName=${entityName}, entityId=${entityId} as erased, but it's not.`);
|
||||
logError(`Entity change id '${id}' has entityName '${entityName}', entityId '${entityId}' as erased, but it's not.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -621,12 +621,12 @@ class ConsistencyChecks {
|
||||
this.fixedIssues = true;
|
||||
this.reloadNeeded = true;
|
||||
|
||||
logFix(`Renamed incorrectly named attributes "${origName}" to ${fixedName}`);
|
||||
logFix(`Renamed incorrectly named attributes '${origName}' to '${fixedName}'`);
|
||||
}
|
||||
else {
|
||||
this.unrecoveredConsistencyErrors = true;
|
||||
|
||||
logFix(`There are incorrectly named attributes "${origName}"`);
|
||||
logFix(`There are incorrectly named attributes '${origName}'`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -670,7 +670,7 @@ class ConsistencyChecks {
|
||||
this.findSyncIssues();
|
||||
|
||||
// root branch should always be expanded
|
||||
sql.execute("UPDATE branches SET isExpanded = 1 WHERE branchId = 'root'");
|
||||
sql.execute("UPDATE branches SET isExpanded = 1 WHERE noteId = 'root'");
|
||||
|
||||
if (!this.unrecoveredConsistencyErrors) {
|
||||
// we run this only if basic checks passed since this assumes basic data consistency
|
||||
@@ -701,13 +701,7 @@ class ConsistencyChecks {
|
||||
let elapsedTimeMs;
|
||||
|
||||
await syncMutexService.doExclusively(() => {
|
||||
const startTimeMs = Date.now();
|
||||
|
||||
this.runDbDiagnostics();
|
||||
|
||||
this.runAllChecksAndFixers();
|
||||
|
||||
elapsedTimeMs = Date.now() - startTimeMs;
|
||||
elapsedTimeMs = this.runChecksInner();
|
||||
});
|
||||
|
||||
if (this.unrecoveredConsistencyErrors) {
|
||||
@@ -721,6 +715,16 @@ class ConsistencyChecks {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
runChecksInner() {
|
||||
const startTimeMs = Date.now();
|
||||
|
||||
this.runDbDiagnostics();
|
||||
|
||||
this.runAllChecksAndFixers();
|
||||
|
||||
return Date.now() - startTimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
function getBlankContent(isProtected, type, mime) {
|
||||
@@ -750,9 +754,14 @@ function runPeriodicChecks() {
|
||||
consistencyChecks.runChecks();
|
||||
}
|
||||
|
||||
function runOnDemandChecks(autoFix) {
|
||||
async function runOnDemandChecks(autoFix) {
|
||||
const consistencyChecks = new ConsistencyChecks(autoFix);
|
||||
consistencyChecks.runChecks();
|
||||
await consistencyChecks.runChecks();
|
||||
}
|
||||
|
||||
function runOnDemandChecksWithoutExclusiveLock(autoFix) {
|
||||
const consistencyChecks = new ConsistencyChecks(autoFix);
|
||||
consistencyChecks.runChecksInner();
|
||||
}
|
||||
|
||||
function runEntityChangesChecks() {
|
||||
@@ -769,5 +778,6 @@ sqlInit.dbReady.then(() => {
|
||||
|
||||
module.exports = {
|
||||
runOnDemandChecks,
|
||||
runOnDemandChecksWithoutExclusiveLock,
|
||||
runEntityChangesChecks
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ const becca = require("../becca/becca");
|
||||
|
||||
let maxEntityChangeId = 0;
|
||||
|
||||
function addEntityChangeWithinstanceId(origEntityChange, instanceId) {
|
||||
function addEntityChangeWithInstanceId(origEntityChange, instanceId) {
|
||||
const ec = {...origEntityChange, instanceId};
|
||||
|
||||
return addEntityChange(ec);
|
||||
@@ -71,7 +71,7 @@ function addEntityChangesForSector(entityName, sector) {
|
||||
}
|
||||
});
|
||||
|
||||
log.info(`Added sector ${sector} of ${entityName} to sync queue in ${Date.now() - startTime}ms.`);
|
||||
log.info(`Added sector ${sector} of '${entityName}' to sync queue in ${Date.now() - startTime}ms.`);
|
||||
}
|
||||
|
||||
function cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey) {
|
||||
@@ -85,45 +85,38 @@ function cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey) {
|
||||
}
|
||||
|
||||
function fillEntityChanges(entityName, entityPrimaryKey, condition = '') {
|
||||
try {
|
||||
cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey);
|
||||
cleanupEntityChangesForMissingEntities(entityName, entityPrimaryKey);
|
||||
|
||||
sql.transactional(() => {
|
||||
const entityIds = sql.getColumn(`SELECT ${entityPrimaryKey} FROM ${entityName}`
|
||||
+ (condition ? ` WHERE ${condition}` : ''));
|
||||
sql.transactional(() => {
|
||||
const entityIds = sql.getColumn(`SELECT ${entityPrimaryKey} FROM ${entityName}`
|
||||
+ (condition ? ` WHERE ${condition}` : ''));
|
||||
|
||||
let createdCount = 0;
|
||||
let createdCount = 0;
|
||||
|
||||
for (const entityId of entityIds) {
|
||||
const existingRows = sql.getValue("SELECT COUNT(1) FROM entity_changes WHERE entityName = ? AND entityId = ?", [entityName, entityId]);
|
||||
for (const entityId of entityIds) {
|
||||
const existingRows = sql.getValue("SELECT COUNT(1) FROM entity_changes WHERE entityName = ? AND entityId = ?", [entityName, entityId]);
|
||||
|
||||
// we don't want to replace existing entities (which would effectively cause full resync)
|
||||
if (existingRows === 0) {
|
||||
createdCount++;
|
||||
// we don't want to replace existing entities (which would effectively cause full resync)
|
||||
if (existingRows === 0) {
|
||||
createdCount++;
|
||||
|
||||
const entity = becca.getEntity(entityName, entityId);
|
||||
const entity = becca.getEntity(entityName, entityId);
|
||||
|
||||
addEntityChange({
|
||||
entityName,
|
||||
entityId,
|
||||
hash: entity.generateHash(),
|
||||
isErased: false,
|
||||
utcDateChanged: entity.getUtcDateChanged(),
|
||||
isSynced: entityName !== 'options' || !!entity.isSynced
|
||||
});
|
||||
}
|
||||
addEntityChange({
|
||||
entityName,
|
||||
entityId,
|
||||
hash: entity.generateHash(),
|
||||
isErased: false,
|
||||
utcDateChanged: entity.getUtcDateChanged(),
|
||||
isSynced: entityName !== 'options' || !!entity.isSynced
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (createdCount > 0) {
|
||||
log.info(`Created ${createdCount} missing entity changes for ${entityName}.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// this is to fix migration from 0.30 to 0.32, can be removed later
|
||||
// see https://github.com/zadam/trilium/issues/557
|
||||
log.error(`Filling entity changes failed for ${entityName} ${entityPrimaryKey} with error "${e.message}", continuing`);
|
||||
}
|
||||
if (createdCount > 0) {
|
||||
log.info(`Created ${createdCount} missing entity changes for ${entityName}.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fillAllEntityChanges() {
|
||||
@@ -145,7 +138,7 @@ module.exports = {
|
||||
addNoteReorderingEntityChange,
|
||||
moveEntityChangeToTop,
|
||||
addEntityChange,
|
||||
addEntityChangeWithinstanceId,
|
||||
addEntityChangeWithInstanceId,
|
||||
fillAllEntityChanges,
|
||||
addEntityChangesForSector,
|
||||
getMaxEntityChangeId: () => maxEntityChangeId
|
||||
|
||||
@@ -214,13 +214,13 @@ function exportToZip(taskContext, branch, format, res) {
|
||||
}
|
||||
|
||||
function findLinks(content, noteMeta) {
|
||||
content = content.replace(/src="[^"]*api\/images\/([a-zA-Z0-9]+)\/[^"]*"/g, (match, targetNoteId) => {
|
||||
content = content.replace(/src="[^"]*api\/images\/([a-zA-Z0-9_]+)\/[^"]*"/g, (match, targetNoteId) => {
|
||||
const url = getTargetUrl(targetNoteId, noteMeta);
|
||||
|
||||
return url ? `src="${url}"` : match;
|
||||
});
|
||||
|
||||
content = content.replace(/href="[^"]*#root[a-zA-Z0-9\/]*\/([a-zA-Z0-9]+)\/?"/g, (match, targetNoteId) => {
|
||||
content = content.replace(/href="[^"]*#root[a-zA-Z0-9_\/]*\/([a-zA-Z0-9_]+)\/?"/g, (match, targetNoteId) => {
|
||||
const url = getTargetUrl(targetNoteId, noteMeta);
|
||||
|
||||
return url ? `href="${url}"` : match;
|
||||
|
||||
@@ -4,8 +4,6 @@ const treeService = require('./tree');
|
||||
const noteService = require('./notes');
|
||||
const becca = require('../becca/becca');
|
||||
const Attribute = require('../becca/entities/attribute');
|
||||
const debounce = require('debounce');
|
||||
const specialNotesService = require("./special_notes");
|
||||
|
||||
function runAttachedRelations(note, relationName, originEntity) {
|
||||
if (!note) {
|
||||
@@ -101,7 +99,7 @@ eventService.subscribe(eventService.ENTITY_CREATED, ({ entityName, entity }) =>
|
||||
noteService.duplicateSubtreeWithoutRoot(templateNote.noteId, note.noteId);
|
||||
}
|
||||
}
|
||||
else if (entity.type === 'label' && entity.name === 'sorted') {
|
||||
else if (entity.type === 'label' && ['sorted', 'sortDirection', 'sortFoldersFirst'].includes(entity.name)) {
|
||||
handleSortedAttribute(entity);
|
||||
}
|
||||
else if (entity.type === 'label') {
|
||||
@@ -110,6 +108,10 @@ eventService.subscribe(eventService.ENTITY_CREATED, ({ entityName, entity }) =>
|
||||
}
|
||||
else if (entityName === 'branches') {
|
||||
runAttachedRelations(entity.getNote(), 'runOnBranchCreation', entity);
|
||||
|
||||
if (entity.parentNote?.hasLabel("sorted")) {
|
||||
treeService.sortNotesIfNeeded(entity.parentNoteId);
|
||||
}
|
||||
}
|
||||
else if (entityName === 'notes') {
|
||||
runAttachedRelations(entity, 'runOnNoteCreation', entity);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const becca = require("../becca/becca");
|
||||
const noteService = require("./notes");
|
||||
const Attribute = require("../becca/entities/attribute.js");
|
||||
|
||||
const LBTPL_ROOT = "_lbTplRoot";
|
||||
const LBTPL_BASE = "_lbTplBase";
|
||||
@@ -10,6 +11,12 @@ const LBTPL_BUILTIN_WIDGET = "_lbTplBuiltinWidget";
|
||||
const LBTPL_SPACER = "_lbTplSpacer";
|
||||
const LBTPL_CUSTOM_WIDGET = "_lbTplCustomWidget";
|
||||
|
||||
/*
|
||||
* Hidden subtree is generated as a "predictable structure" which means that it avoids generating random IDs to always
|
||||
* produce same structure. This is needed because it is run on multiple instances in the sync cluster which might produce
|
||||
* duplicate subtrees. This way, all instances will generate the same structure with same IDs.
|
||||
*/
|
||||
|
||||
const HIDDEN_SUBTREE_DEFINITION = {
|
||||
id: '_hidden',
|
||||
title: 'Hidden Notes',
|
||||
@@ -237,13 +244,7 @@ function checkHiddenSubtreeRecursively(parentNoteId, item) {
|
||||
}
|
||||
|
||||
let note = becca.notes[item.id];
|
||||
let branch = becca.branches[item.id];
|
||||
|
||||
const attrs = [...(item.attributes || [])];
|
||||
|
||||
if (item.icon) {
|
||||
attrs.push({ type: 'label', name: 'iconClass', value: `bx ${item.icon}` });
|
||||
}
|
||||
let branch;
|
||||
|
||||
if (!note) {
|
||||
({note, branch} = noteService.createNewNote({
|
||||
@@ -254,27 +255,35 @@ function checkHiddenSubtreeRecursively(parentNoteId, item) {
|
||||
content: '',
|
||||
ignoreForbiddenParents: true
|
||||
}));
|
||||
} else {
|
||||
branch = note.getParentBranches().find(branch => branch.parentNoteId === parentNoteId);
|
||||
}
|
||||
|
||||
if (item.type === 'launcher') {
|
||||
if (item.command) {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_COMMAND });
|
||||
attrs.push({ type: 'label', name: 'command', value: item.command });
|
||||
} else if (item.builtinWidget) {
|
||||
if (item.builtinWidget === 'spacer') {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_SPACER });
|
||||
attrs.push({ type: 'label', name: 'baseSize', value: item.baseSize });
|
||||
attrs.push({ type: 'label', name: 'growthFactor', value: item.growthFactor });
|
||||
} else {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_BUILTIN_WIDGET });
|
||||
}
|
||||
const attrs = [...(item.attributes || [])];
|
||||
|
||||
attrs.push({ type: 'label', name: 'builtinWidget', value: item.builtinWidget });
|
||||
} else if (item.targetNoteId) {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_NOTE_LAUNCHER });
|
||||
attrs.push({ type: 'relation', name: 'target', value: item.targetNoteId });
|
||||
if (item.icon) {
|
||||
attrs.push({ type: 'label', name: 'iconClass', value: `bx ${item.icon}` });
|
||||
}
|
||||
|
||||
if (item.type === 'launcher') {
|
||||
if (item.command) {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_COMMAND });
|
||||
attrs.push({ type: 'label', name: 'command', value: item.command });
|
||||
} else if (item.builtinWidget) {
|
||||
if (item.builtinWidget === 'spacer') {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_SPACER });
|
||||
attrs.push({ type: 'label', name: 'baseSize', value: item.baseSize });
|
||||
attrs.push({ type: 'label', name: 'growthFactor', value: item.growthFactor });
|
||||
} else {
|
||||
throw new Error(`No action defined for launcher ${JSON.stringify(item)}`);
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_BUILTIN_WIDGET });
|
||||
}
|
||||
|
||||
attrs.push({ type: 'label', name: 'builtinWidget', value: item.builtinWidget });
|
||||
} else if (item.targetNoteId) {
|
||||
attrs.push({ type: 'relation', name: 'template', value: LBTPL_NOTE_LAUNCHER });
|
||||
attrs.push({ type: 'relation', name: 'target', value: item.targetNoteId });
|
||||
} else {
|
||||
throw new Error(`No action defined for launcher ${JSON.stringify(item)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,8 +308,17 @@ function checkHiddenSubtreeRecursively(parentNoteId, item) {
|
||||
}
|
||||
|
||||
for (const attr of attrs) {
|
||||
if (!note.hasAttribute(attr.type, attr.name)) {
|
||||
note.addAttribute(attr.type, attr.name, attr.value);
|
||||
const attrId = note.noteId + "_" + attr.type.charAt(0) + attr.name;
|
||||
|
||||
if (!note.getAttributes().find(attr => attr.attributeId === attrId)) {
|
||||
new Attribute({
|
||||
attributeId: attrId,
|
||||
noteId: note.noteId,
|
||||
type: attr.type,
|
||||
name: attr.name,
|
||||
value: attr.value,
|
||||
isInheritable: false
|
||||
}).save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const sanitizeHtml = require('sanitize-html');
|
||||
const sanitizeUrl = require('@braintree/sanitize-url').sanitizeUrl;
|
||||
|
||||
// intended mainly as protection against XSS via import
|
||||
// secondarily it (partly) protects against "CSS takeover"
|
||||
@@ -28,7 +29,8 @@ function sanitize(dirtyHtml) {
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
|
||||
'li', 'b', 'i', 'strong', 'em', 'strike', 's', 'del', 'abbr', 'code', 'hr', 'br', 'div',
|
||||
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'section', 'img',
|
||||
'figure', 'figcaption', 'span', 'label', 'input'
|
||||
'figure', 'figcaption', 'span', 'label', 'input',
|
||||
'en-media' // for ENEX import
|
||||
],
|
||||
allowedAttributes: {
|
||||
'a': [ 'href', 'class', 'data-note-path' ],
|
||||
@@ -41,6 +43,7 @@ function sanitize(dirtyHtml) {
|
||||
'code': [ 'class' ],
|
||||
'ul': [ 'class' ],
|
||||
'table': [ 'class' ],
|
||||
'en-media': [ 'hash' ]
|
||||
},
|
||||
allowedSchemes: ['http', 'https', 'ftp', 'mailto', 'data', 'evernote'],
|
||||
transformTags,
|
||||
@@ -48,5 +51,6 @@ function sanitize(dirtyHtml) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sanitize
|
||||
sanitize,
|
||||
sanitizeUrl
|
||||
};
|
||||
|
||||
@@ -8,13 +8,19 @@ const noteService = require("../notes");
|
||||
const imageService = require("../image");
|
||||
const protectedSessionService = require('../protected_session');
|
||||
const htmlSanitizer = require("../html_sanitizer");
|
||||
const attributeService = require("../attributes");
|
||||
const {sanitizeAttributeName} = require("../sanitize_attribute_name.js");
|
||||
|
||||
// date format is e.g. 20181121T193703Z
|
||||
/**
|
||||
* date format is e.g. 20181121T193703Z or 2013-04-14T16:19:00.000Z (Mac evernote, see #3496)
|
||||
* @returns trilium date format, e.g. 2013-04-14 16:19:00.000Z
|
||||
*/
|
||||
function parseDate(text) {
|
||||
// insert - and : to make it ISO format
|
||||
text = `${text.substr(0, 4)}-${text.substr(4, 2)}-${text.substr(6, 2)} ${text.substr(9, 2)}:${text.substr(11, 2)}:${text.substr(13, 2)}.000Z`;
|
||||
// convert ISO format to the "20181121T193703Z" format
|
||||
text = text.replace(/[-:]/g, "");
|
||||
|
||||
// insert - and : to convert it to trilium format
|
||||
text = text.substr(0, 4) + "-" + text.substr(4, 2) + "-" + text.substr(6, 2)
|
||||
+ " " + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + ".000Z";
|
||||
|
||||
return text;
|
||||
}
|
||||
@@ -115,7 +121,7 @@ function importEnex(taskContext, file, parentNote) {
|
||||
let labelName = currentTag;
|
||||
|
||||
if (labelName === 'source-url') {
|
||||
labelName = 'sourceUrl';
|
||||
labelName = 'pageUrl';
|
||||
}
|
||||
|
||||
labelName = sanitizeAttributeName(labelName);
|
||||
@@ -139,7 +145,7 @@ function importEnex(taskContext, file, parentNote) {
|
||||
else if (currentTag === 'source-url') {
|
||||
resource.attributes.push({
|
||||
type: 'label',
|
||||
name: 'sourceUrl',
|
||||
name: 'pageUrl',
|
||||
value: text
|
||||
});
|
||||
}
|
||||
@@ -263,7 +269,7 @@ function importEnex(taskContext, file, parentNote) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mediaRegex = new RegExp(`<en-media hash="${hash}"[^>]*>`, 'g');
|
||||
const mediaRegex = new RegExp(`<en-media [^>]*hash="${hash}"[^>]*>`, 'g');
|
||||
|
||||
resource.mime = resource.mime || "application/octet-stream";
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
title: noteTitle,
|
||||
content: '',
|
||||
noteId: noteId,
|
||||
type: resolveNoteType(noteMeta.type),
|
||||
type: resolveNoteType(noteMeta?.type),
|
||||
mime: noteMeta ? noteMeta.mime : 'text/html',
|
||||
prefix: noteMeta ? noteMeta.prefix : '',
|
||||
isExpanded: noteMeta ? noteMeta.isExpanded : false,
|
||||
@@ -231,6 +231,13 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
absUrl += `${absUrl.length > 0 ? '/' : ''}${url}`;
|
||||
|
||||
const {noteMeta} = getMeta(absUrl);
|
||||
|
||||
if (!noteMeta) {
|
||||
log.info(`Could not find note meta for URL '${absUrl}'.`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const targetNoteId = getNoteId(noteMeta, absUrl);
|
||||
return targetNoteId;
|
||||
}
|
||||
@@ -312,6 +319,10 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
|
||||
const targetNoteId = getNoteIdFromRelativeUrl(url, filePath);
|
||||
|
||||
if (!targetNoteId) {
|
||||
return match;
|
||||
}
|
||||
|
||||
return `src="api/images/${targetNoteId}/${path.basename(url)}"`;
|
||||
});
|
||||
|
||||
@@ -329,6 +340,10 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
|
||||
|
||||
const targetNoteId = getNoteIdFromRelativeUrl(url, filePath);
|
||||
|
||||
if (!targetNoteId) {
|
||||
return match;
|
||||
}
|
||||
|
||||
return `href="#root/${targetNoteId}"`;
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ async function migrate() {
|
||||
}
|
||||
|
||||
fs.readdirSync(resourceDir.MIGRATIONS_DIR).forEach(file => {
|
||||
const match = file.match(/([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)/);
|
||||
const match = file.match(/^([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)$/);
|
||||
|
||||
if (match) {
|
||||
const dbVersion = parseInt(match[1]);
|
||||
@@ -62,9 +62,10 @@ async function migrate() {
|
||||
log.info(`Migration to version ${mig.dbVersion} has been successful.`);
|
||||
} catch (e) {
|
||||
log.error(`error during migration to version ${mig.dbVersion}: ${e.stack}`);
|
||||
log.error("migration failed, crashing hard"); // this is not very user friendly :-/
|
||||
log.error("migration failed, crashing hard"); // this is not very user-friendly :-/
|
||||
|
||||
utils.crash();
|
||||
break; // crash() above does not seem to work right away
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -155,6 +155,9 @@ function createNewNote(params) {
|
||||
cls.disableEntityEvents();
|
||||
}
|
||||
|
||||
// TODO: think about what can happen if the note already exists with the forced ID
|
||||
// I guess on DB it's going to be fine, but becca references between entities
|
||||
// might get messed up (two Note instance for the same ID existing in the references)
|
||||
note = new Note({
|
||||
noteId: params.noteId, // optionally can force specific noteId
|
||||
title: params.title,
|
||||
|
||||
@@ -51,9 +51,9 @@ function runNotesWithLabel(runAttrValue) {
|
||||
}
|
||||
|
||||
sqlInit.dbReady.then(() => {
|
||||
if (!process.env.TRILIUM_SAFE_MODE) {
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
cls.init(() => hiddenSubtreeService.checkHiddenSubtree());
|
||||
|
||||
if (!process.env.TRILIUM_SAFE_MODE) {
|
||||
setTimeout(cls.wrap(() => runNotesWithLabel('backendStartup')), 10 * 1000);
|
||||
|
||||
setInterval(cls.wrap(() => runNotesWithLabel('hourly')), 3600 * 1000);
|
||||
|
||||
@@ -48,14 +48,13 @@ class OrderByAndLimitExp extends Expression {
|
||||
}
|
||||
|
||||
// if both are numbers then parse them for numerical comparison
|
||||
// beware that isNaN will return false for empty string and null
|
||||
if (valA.trim() !== "" && valB.trim() !== "" && !isNaN(valA) && !isNaN(valB)) {
|
||||
if (this.isNumber(valA) && this.isNumber(valB)) {
|
||||
valA = parseFloat(valA);
|
||||
valB = parseFloat(valB);
|
||||
}
|
||||
|
||||
if (!valA && !valB) {
|
||||
// the attribute is not defined in either note so continue to next order definition
|
||||
// the attribute value is empty/zero in both notes so continue to the next order definition
|
||||
continue;
|
||||
} else if (!valB || valA < valB) {
|
||||
return smaller;
|
||||
@@ -77,6 +76,17 @@ class OrderByAndLimitExp extends Expression {
|
||||
|
||||
return noteSet;
|
||||
}
|
||||
|
||||
isNumber(x) {
|
||||
if (typeof x === 'number') {
|
||||
return true;
|
||||
} else if (typeof x === 'string') {
|
||||
// isNaN will return false for blank string
|
||||
return x.trim() !== "" && !isNaN(x);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OrderByAndLimitExp;
|
||||
|
||||
@@ -24,6 +24,7 @@ class SearchContext {
|
||||
this.fuzzyAttributeSearch = !!params.fuzzyAttributeSearch;
|
||||
this.highlightedTokens = [];
|
||||
this.originalQuery = "";
|
||||
this.fulltextQuery = ""; // complete fulltext part
|
||||
// if true, becca does not have (up-to-date) information needed to process the query
|
||||
// and some extra data needs to be loaded before executing
|
||||
this.dbLoadNeeded = false;
|
||||
|
||||
@@ -17,18 +17,22 @@ class SearchResult {
|
||||
return this.notePathArray[this.notePathArray.length - 1];
|
||||
}
|
||||
|
||||
computeScore(tokens) {
|
||||
computeScore(fulltextQuery, tokens) {
|
||||
this.score = 0;
|
||||
|
||||
const note = becca.notes[this.noteId];
|
||||
|
||||
if (note.title.toLowerCase() === fulltextQuery) {
|
||||
this.score += 100; // high reward for exact match #3470
|
||||
}
|
||||
|
||||
// notes with matches on its own note title as opposed to ancestors or descendants
|
||||
this.addScoreForStrings(tokens, note.title, 1.5);
|
||||
|
||||
// matches in attributes don't get extra points and thus are implicitly valued less than note path matches
|
||||
|
||||
this.addScoreForStrings(tokens, this.notePathTitle, 1);
|
||||
|
||||
// add one more time for note title alone (already contained in the notePathTitle),
|
||||
// thus preferring notes with matches on its own note title as opposed to ancestors or descendants
|
||||
const note = becca.notes[this.noteId];
|
||||
this.addScoreForStrings(tokens, note.title, 1.5);
|
||||
|
||||
if (note.isInHiddenSubtree()) {
|
||||
this.score = this.score / 2;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
function lex(str) {
|
||||
str = str.toLowerCase();
|
||||
|
||||
let fulltextQuery = "";
|
||||
const fulltextTokens = [];
|
||||
const expressionTokens = [];
|
||||
|
||||
@@ -37,6 +38,8 @@ function lex(str) {
|
||||
expressionTokens.push(rec);
|
||||
} else {
|
||||
fulltextTokens.push(rec);
|
||||
|
||||
fulltextQuery = str.substr(0, endIndex + 1);
|
||||
}
|
||||
|
||||
currentWord = '';
|
||||
@@ -129,7 +132,10 @@ function lex(str) {
|
||||
|
||||
finishWord(str.length - 1);
|
||||
|
||||
fulltextQuery = fulltextQuery.trim();
|
||||
|
||||
return {
|
||||
fulltextQuery,
|
||||
fulltextTokens,
|
||||
expressionTokens
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ function findResultsWithExpression(expression, searchContext) {
|
||||
.filter(note => !!note);
|
||||
|
||||
for (const res of searchResults) {
|
||||
res.computeScore(searchContext.highlightedTokens);
|
||||
res.computeScore(searchContext.fulltextQuery, searchContext.highlightedTokens);
|
||||
}
|
||||
|
||||
if (!noteSet.sorted) {
|
||||
@@ -195,7 +195,9 @@ function findResultsWithExpression(expression, searchContext) {
|
||||
}
|
||||
|
||||
function parseQueryToExpression(query, searchContext) {
|
||||
const {fulltextTokens, expressionTokens} = lex(query);
|
||||
const {fulltextQuery, fulltextTokens, expressionTokens} = lex(query);
|
||||
searchContext.fulltextQuery = fulltextQuery;
|
||||
|
||||
let structuredExpressionTokens;
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Search string is lower cased for case insensitive comparison. But when retrieving properties
|
||||
* we need case sensitive form so we have this translation object.
|
||||
* Search string is lower cased for case-insensitive comparison. But when retrieving properties
|
||||
* we need case-sensitive form, so we have this translation object.
|
||||
*/
|
||||
const PROP_MAPPING = {
|
||||
"noteid": "noteId",
|
||||
|
||||
@@ -77,7 +77,6 @@ async function createInitialDatabase() {
|
||||
rootNote.setContent('');
|
||||
|
||||
new Branch({
|
||||
branchId: 'root',
|
||||
noteId: 'root',
|
||||
parentNoteId: 'none',
|
||||
isExpanded: true,
|
||||
|
||||
@@ -15,7 +15,9 @@ function get(name) {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSyncServerHost: () => get('syncServerHost'),
|
||||
// env variable is the easiest way to guarantee we won't overwrite prod data during development
|
||||
// after copying prod document/data directory
|
||||
getSyncServerHost: () => process.env.TRILIUM_SYNC_SERVER_HOST || get('syncServerHost'),
|
||||
isSyncSetup: () => {
|
||||
const syncServerHost = get('syncServerHost');
|
||||
|
||||
|
||||
+11
-10
@@ -42,7 +42,7 @@ function updateEntity(entityChange, entityRow, instanceId) {
|
||||
}
|
||||
}
|
||||
|
||||
function updateNormalEntity(remoteEntityChange, entity, instanceId) {
|
||||
function updateNormalEntity(remoteEntityChange, remoteEntityRow, instanceId) {
|
||||
const localEntityChange = sql.getRow(`
|
||||
SELECT utcDateChanged, hash, isErased
|
||||
FROM entity_changes
|
||||
@@ -54,7 +54,7 @@ function updateNormalEntity(remoteEntityChange, entity, instanceId) {
|
||||
|
||||
sql.execute(`DELETE FROM ${remoteEntityChange.entityName} WHERE ${primaryKey} = ?`, remoteEntityChange.entityId);
|
||||
|
||||
entityChangesService.addEntityChangeWithinstanceId(remoteEntityChange, instanceId);
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEntityChange, instanceId);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -65,13 +65,13 @@ function updateNormalEntity(remoteEntityChange, entity, instanceId) {
|
||||
|| localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update
|
||||
) {
|
||||
if (['note_contents', 'note_revision_contents'].includes(remoteEntityChange.entityName)) {
|
||||
entity.content = handleContent(entity.content);
|
||||
remoteEntityRow.content = handleContent(remoteEntityRow.content);
|
||||
}
|
||||
|
||||
sql.transactional(() => {
|
||||
sql.replace(remoteEntityChange.entityName, entity);
|
||||
sql.replace(remoteEntityChange.entityName, remoteEntityRow);
|
||||
|
||||
entityChangesService.addEntityChangeWithinstanceId(remoteEntityChange, instanceId);
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEntityChange, instanceId);
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -86,15 +86,16 @@ function updateNoteReordering(entityChange, entity, instanceId) {
|
||||
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [entity[key], key]);
|
||||
}
|
||||
|
||||
entityChangesService.addEntityChangeWithinstanceId(entityChange, instanceId);
|
||||
entityChangesService.addEntityChangeWithInstanceId(entityChange, instanceId);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleContent(content) {
|
||||
// we always use Buffer object which is different from normal saving - there we use simple string type for "string notes"
|
||||
// the problem is that in general it's not possible to whether a note_content is string note or note (syncs can arrive out of order)
|
||||
// we always use Buffer object which is different from normal saving - there we use simple string type for
|
||||
// "string notes". The problem is that in general it's not possible to detect whether a note_content
|
||||
// is string note or note (syncs can arrive out of order)
|
||||
content = content === null ? null : Buffer.from(content, 'base64');
|
||||
|
||||
if (content && content.byteLength === 0) {
|
||||
@@ -109,7 +110,7 @@ function eraseEntity(entityChange, instanceId) {
|
||||
const {entityName, entityId} = entityChange;
|
||||
|
||||
if (!["notes", "note_contents", "branches", "attributes", "note_revisions", "note_revision_contents"].includes(entityName)) {
|
||||
log.error(`Cannot erase entity ${entityName}, id ${entityId}`);
|
||||
log.error(`Cannot erase entity '${entityName}', id '${entityId}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -119,7 +120,7 @@ function eraseEntity(entityChange, instanceId) {
|
||||
|
||||
eventService.emit(eventService.ENTITY_DELETE_SYNCED, { entityName, entityId });
|
||||
|
||||
entityChangesService.addEntityChangeWithinstanceId(entityChange, instanceId);
|
||||
entityChangesService.addEntityChangeWithInstanceId(entityChange, instanceId);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -291,6 +291,10 @@ function deferred() {
|
||||
}
|
||||
|
||||
function removeDiacritic(str) {
|
||||
if (!str) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return str.normalize("NFD").replace(/\p{Diacritic}/gu, "");
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -7,6 +7,7 @@ const shacaLoader = require("./shaca/shaca_loader");
|
||||
const shareRoot = require("./share_root");
|
||||
const contentRenderer = require("./content_renderer");
|
||||
const assetPath = require("../services/asset_path");
|
||||
const appPath = require("../services/app_path");
|
||||
|
||||
function getSharedSubTreeRoot(note) {
|
||||
if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
|
||||
@@ -111,7 +112,8 @@ function register(router) {
|
||||
content,
|
||||
isEmpty,
|
||||
subRoot,
|
||||
assetPath
|
||||
assetPath,
|
||||
appPath
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>,
|
||||
triliumVersion: "<%= triliumVersion %>",
|
||||
assetPath: "<%= assetPath %>",
|
||||
appPath: "<%= appPath %>",
|
||||
TRILIUM_SAFE_MODE: <%= !!process.env.TRILIUM_SAFE_MODE %>
|
||||
};
|
||||
</script>
|
||||
@@ -80,7 +81,7 @@
|
||||
$("body").show();
|
||||
</script>
|
||||
|
||||
<script src="<%= assetPath %>/app/desktop.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/desktop.js" crossorigin type="module"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<%= assetPath %>/libraries/boxicons/css/boxicons.min.css">
|
||||
|
||||
|
||||
@@ -115,9 +115,10 @@
|
||||
csrfToken: '<%= csrfToken %>',
|
||||
isDev: <%= isDev %>,
|
||||
appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>,
|
||||
isMainWindow: true,
|
||||
isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>,
|
||||
assetPath: "<%= assetPath %>",
|
||||
isMainWindow: true,
|
||||
appPath: "<%= appPath %>",
|
||||
TRILIUM_SAFE_MODE: <%= !!process.env.TRILIUM_SAFE_MODE %>
|
||||
};
|
||||
</script>
|
||||
@@ -132,7 +133,7 @@
|
||||
<link href="<%= assetPath %>/libraries/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="<%= assetPath %>/libraries/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script src="<%= assetPath %>/app/mobile.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/mobile.js" crossorigin type="module"></script>
|
||||
|
||||
<link href="api/fonts" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/ckeditor-theme.css" rel="stylesheet">
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@
|
||||
|
||||
<script src="<%= assetPath %>/libraries/knockout.min.js"></script>
|
||||
|
||||
<script src="<%= assetPath %>/app/setup.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/setup.js" crossorigin type="module"></script>
|
||||
<link href="<%= assetPath %>/stylesheets/theme-light.css" rel="stylesheet">
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<% } else { %>
|
||||
<link rel="shortcut icon" href="../favicon.ico">
|
||||
<% } %>
|
||||
<script src="../<%= assetPath %>/app/share.js"></script>
|
||||
<script src="../<%= appPath %>/share.js"></script>
|
||||
<% if (!note.hasLabel("shareOmitDefaultCss")) { %>
|
||||
<link href="../<%= assetPath %>/libraries/normalize.min.css" rel="stylesheet">
|
||||
<link href="../<%= assetPath %>/stylesheets/share.css" rel="stylesheet">
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
POST {{triliumHost}}/etapi/create-note
|
||||
Authorization: {{authToken}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"parentNoteId": "root",
|
||||
"title": "Hello",
|
||||
"type": "code",
|
||||
"mime": "text/plain",
|
||||
"content": "Hi there!"
|
||||
}
|
||||
|
||||
> {% client.global.set("createdNoteId", response.body.note.noteId); %}
|
||||
|
||||
###
|
||||
|
||||
POST {{triliumHost}}/etapi/notes/{{createdNoteId}}/note-revision
|
||||
Authorization: {{authToken}}
|
||||
Content-Type: text/plain
|
||||
|
||||
Changed content
|
||||
|
||||
> {% client.assert(response.status === 204); %}
|
||||
@@ -20,7 +20,7 @@ Content-Type: text/plain
|
||||
|
||||
Changed content
|
||||
|
||||
> {% client.assert(response.status === 200); %}
|
||||
> {% client.assert(response.status === 204); %}
|
||||
|
||||
###
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
mobile: './src/public/app/desktop.js',
|
||||
},
|
||||
output: {
|
||||
publicPath: `/${assetPath}/app-dist/`,
|
||||
publicPath: `${assetPath}/app-dist/`,
|
||||
path: path.resolve(__dirname, 'src/public/app-dist'),
|
||||
filename: 'desktop.js'
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user