Compare commits

..

1 Commits

Author SHA1 Message Date
zadam
baed93e749 algolia v1 upgrade 2021-12-14 22:44:54 +01:00
879 changed files with 34437 additions and 83251 deletions

View File

@@ -3,11 +3,18 @@ description: Report a bug
title: "(Bug report) "
labels: "Type: Bug"
body:
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I have searched the [issue tracker](https://www.github.com/zadam/trilium/issues) for a bug report that matches the one I want to file, without success.
required: true
- type: input
attributes:
label: Trilium Version
description: What version of Trilium are you using?
placeholder: 0.57.0-beta
placeholder: 0.48.0-beta
validations:
required: true
- type: dropdown
@@ -23,7 +30,7 @@ body:
required: true
- type: dropdown
attributes:
label: What is your setup?
label: What is your setup?
description: https://github.com/zadam/trilium/wiki#choose-the-setup
options:
- Local (no sync)
@@ -40,13 +47,17 @@ body:
required: true
- type: textarea
attributes:
label: Description
description: A clear and concise description of the bug and any additional information.
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
attributes:
label: Error logs
description: Please provide error logs, see [wiki page](https://github.com/zadam/trilium/wiki/Error-logs) for instructions on how to submit them.
label: Actual Behavior
description: A clear description of what actually happens.
validations:
required: false
required: true
- type: textarea
attributes:
label: Additional Information
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.

View File

@@ -1,8 +1,15 @@
name: Feature Request
description: Ask for a new feature to be added
description: Report a bug
title: "(Feature request) "
labels: "Type: Enhancement"
body:
- type: checkboxes
attributes:
label: Preflight Checklist
description: Please ensure you've completed all of the following.
options:
- label: I have searched the [issue tracker](https://www.github.com/zadam/trilium/issues) for a feature request that matches the one I want to file, without success.
required: true
- type: textarea
attributes:
label: Describe feature

5
.gitignore vendored
View File

@@ -8,7 +8,4 @@ yarn-error.log
config.ini
cert.key
cert.crt
server-package.json
.idea/httpRequests/
data/
tmp/
server-package.json

View File

@@ -2,7 +2,7 @@ image:
file: .gitpod.dockerfile
tasks:
- before: nvm install 16.19.0 && nvm use 16.19.0
- before: nvm install 16.13.1 && nvm use 16.13.1
init: npm install
command: npm run start-server

2
.idea/misc.xml generated
View File

@@ -3,7 +3,7 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="openjdk-16" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

3
.vscode/launch.json vendored
View File

@@ -9,8 +9,7 @@
"<node_internals>/**"
],
"env": {
"TRILIUM_ENV": "dev",
"TRILIUM_DATA_DIR": "./data"
"TRILIUM_ENV": "dev"
},
"outputCapture": "std",
"program": "${workspaceFolder}/src/www"

View File

@@ -1 +0,0 @@
Please treat each other with respect and understanding.

View File

@@ -1,13 +0,0 @@
#!/bin/sh
# Try connecting to /api/health-check using both http and https.
# TODO: we should only be connecting with the actual protocol that is enabled
# TODO: this assumes we use the default port 8080
for proto in http https; do
if wget --spider -S "$proto://127.0.0.1:8080/api/health-check" 2>&1 | awk 'NR==2' | grep -w "HTTP/1.1 200 OK" ; then
exit 0
fi
done
exit 1

View File

@@ -1,12 +1,8 @@
# !!! Don't try to build this Dockerfile directly, run it through bin/build-docker.sh script !!!
FROM node:16.19.0-alpine
FROM node:16.13.1-alpine
# Create app directory
WORKDIR /usr/src/app
# Bundle app source
COPY . .
COPY server-package.json package.json
# Install app dependencies
@@ -21,22 +17,13 @@ RUN set -x \
nasm \
libpng-dev \
python3 \
&& npm install \
&& apk del .build-dependencies \
&& npm run webpack \
&& npm prune --omit=dev \
&& 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
&& npm install --production \
&& apk del .build-dependencies
# Some setup tools need to be kept
RUN apk add --no-cache su-exec shadow
# Bundle app source
COPY . .
# Add application user and setup proper volume permissions
RUN adduser -s /bin/false node; exit 0
USER node
# Start the application
EXPOSE 8080
CMD [ "./start-docker.sh" ]
HEALTHCHECK CMD sh DockerHealthcheck.sh
CMD [ "node", "./src/www" ]

View File

@@ -1,56 +1,45 @@
# Trilium Notes
# Trilium笔记
[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)
[![Join the chat at https://gitter.im/trilium-notes/Lobby](https://badges.gitter.im/trilium-notes/Lobby.svg)](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)以快速了解:
![](https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png)
Ukraine is currently suffering from Russian aggression, please consider donating to [one of these charities](https://old.reddit.com/r/ukraine/comments/s6g5un/want_to_support_ukraine_heres_a_list_of_charities/).
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
## 特性
* 笔记可以排列成任意深的树。单个笔记可以放在树中的多个位置(请参阅[克隆](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)功能
* 使用[网页剪藏](https://github.com/zadam/trilium/wiki/Web-clipper)轻松保存互联网上的内容
* [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内容
## 构建
Trilium 可以用作桌面应用程序LinuxWindows或服务器Linux上托管的 Web 应用程序。虽然有 macOS 版本的桌面应用程序,但[不受支持](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support)。
Trilium是作为桌面应用程序LinuxWindows或服务器上托管的Web应用程序Linux提供的。Mac OS桌面版本可用,但[不受支持](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support)。
* 如果要在桌面上使用 Trilium请从[最新版本](https://github.com/zadam/trilium/releases/latest)下载适用于您平台的二进制版本,解压缩该软件包并运行`trilium`可执行文件。
* 如果要在服务器上安装 Trilium参考[此页面](https://github.com/zadam/trilium/wiki/Server-installation)。
* 当前仅支持(测试)最近发布的 ChromeFirefox 浏览器。
Trilium 也提供 Flatpak
[<img width="240" src="https://flathub.org/assets/badges/flathub-badge-en.png">](https://flathub.org/apps/details/com.github.zadam.trilium)
* 如果要在桌面上使用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)。
* 当前仅支持(经过测试)最新的ChromeFirefox浏览器。
## 文档
[有关文档页面的完整列表,请参见 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的灵感。
## 贡献
@@ -58,7 +47,7 @@ Trilium 也提供 Flatpak
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/zadam/trilium)
者克隆本仓库到本地,并运行
在本地克隆并运行
```
npm install
@@ -67,15 +56,7 @@ 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)
## 捐赠
你可以通过 GitHub Sponsors[PayPal](https://paypal.me/za4am) 或者比特币 (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2) 来捐赠。
## 许可证
本程序是自由软件:你可以再发布本软件和/或修改本软件,只要你遵循 Free Software Foundation 发布的 GNU Affero General Public License 的第三版或者任何(由你选择)更晚的版本。
* [jsPlumb](https://github.com/jsplumb/jsplumb)强大的可视化连接库。- 用于[关系图](https://github.com/zadam/trilium/wiki/Relation-map)和[链接图](https://github.com/zadam/trilium/wiki/Link-map)

View File

@@ -7,10 +7,6 @@ Trilium Notes is a hierarchical note taking application with focus on building l
![](https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png)
Ukraine is currently defending itself from Russian aggression, please consider [donating to Ukrainian Army or humanitarian charities](https://standforukraine.com/).
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
## Features
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes))
@@ -20,13 +16,9 @@ Ukraine is currently defending itself from Russian aggression, please consider [
* Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions)
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
* there's a [3rd party service for hosting synchronisation server](https://trilium.cc/paid-hosting)
* [Sharing](https://github.com/zadam/trilium/wiki/Sharing) (publishing) notes to public internet
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) with per-note granularity
* Sketching diagrams with built-in Excalidraw (note type "canvas")
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map) for visualizing notes and their relations
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
* [REST API](https://github.com/zadam/trilium/wiki/ETAPI) for automation
* Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
@@ -41,10 +33,6 @@ Trilium is provided as either desktop application (Linux and Windows) or web app
* If you want to install Trilium on server, follow [this page](https://github.com/zadam/trilium/wiki/Server-installation).
* Currently only recent Chrome and Firefox are supported (tested) browsers.
Trilium is also provided as a Flatpak:
[<img width="240" src="https://flathub.org/assets/badges/flathub-badge-en.png">](https://flathub.org/apps/details/com.github.zadam.trilium)
## Documentation
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
@@ -70,10 +58,6 @@ npm run start-server
* [CodeMirror](https://github.com/codemirror/CodeMirror) - code editor with support for huge amount of languages
* [jsPlumb](https://github.com/jsplumb/jsplumb) - visual connectivity library without competition. Used in [relation maps](https://github.com/zadam/trilium/wiki/Relation-map) and [link maps](https://github.com/zadam/trilium/wiki/Link-map)
## Donating
You can donate using GitHub Sponsors, [PayPal](https://paypal.me/za4am) or Bitcoin (bitcoin:bc1qv3svjn40v89mnkre5vyvs2xw6y8phaltl385d2).
## License
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

View File

@@ -7,10 +7,6 @@ Trilium Notes это приложение для заметок с иера
![](https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png)
Ukraine is currently suffering from Russian aggression, please consider donating to [one of these charities](https://old.reddit.com/r/ukraine/comments/s6g5un/want_to_support_ukraine_heres_a_list_of_charities/).
<img src="https://upload.wikimedia.org/wikipedia/commons/4/49/Flag_of_Ukraine.svg" alt="drawing" width="600"/>
## Возможности
* Заметки можно расположить в виде дерева произвольной глубины. Отдельную заметку можно разместить в нескольких местах дерева (см. [клонирование](https://github.com/zadam/trilium/wiki/Cloning-notes))

3
TODO Normal file
View File

@@ -0,0 +1,3 @@
- new icon
- polish becca entities API
- separate private and public APIs in becca entities

View File

@@ -27,11 +27,6 @@ cp images/app-icons/png/128x128.png $BUILD_DIR/icon.png
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
cp -r dump-db $BUILD_DIR/
rm -rf $BUILD_DIR/dump-db/node_modules
cp bin/tpl/trilium-portable.sh $BUILD_DIR/
chmod 755 $BUILD_DIR/trilium-portable.sh

View File

@@ -23,11 +23,6 @@ rm -rf $BUILD_DIR
# Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
cp -r dump-db $BUILD_DIR/
rm -rf $BUILD_DIR/dump-db/node_modules
echo "Zipping mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=16.19.0
NODE_VERSION=16.13.1
if [ "$1" != "DONTCOPY" ]
then
@@ -20,19 +20,12 @@ rm -r $PKG_DIR/node/lib/node_modules/npm
rm -r $PKG_DIR/node/include/node
rm -r $PKG_DIR/node_modules/electron*
rm -r $PKG_DIR/webpack*
rm -r $PKG_DIR/electron.js
cp -r bin/better-sqlite3/linux-server-better_sqlite3.node $PKG_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node
printf "#!/bin/sh\n./node/bin/node src/www" > $PKG_DIR/trilium.sh
chmod 755 $PKG_DIR/trilium.sh
cp bin/tpl/anonymize-database.sql $PKG_DIR/
cp -r dump-db $PKG_DIR/
rm -rf $PKG_DIR/dump-db/node_modules
VERSION=`jq -r ".version" package.json`
cd dist

View File

@@ -25,12 +25,9 @@ mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
cp bin/tpl/anonymize-database.sql $BUILD_DIR/
cp -r dump-db $BUILD_DIR/
rm -rf $BUILD_DIR/dump-db/node_modules
cp bin/tpl/trilium-{portable,no-cert-check,safe-mode}.bat $BUILD_DIR/
cp bin/tpl/trilium-portable.bat $BUILD_DIR/
cp bin/tpl/trilium-no-cert-check.bat $BUILD_DIR/
cp bin/tpl/trilium-safe-mode.bat $BUILD_DIR/
echo "Zipping windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -5,7 +5,7 @@ if [[ $# -eq 0 ]] ; then
exit 1
fi
n exec 16.19.0 npm run webpack
n exec 16.13.1 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.19.0 npm install --only=prod)
(cd $DIR && n exec 16.13.1 npm install --only=prod)
# cleanup of useless files in dependencies
rm -r $DIR/node_modules/image-q/demo
@@ -44,7 +44,8 @@ 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 -r $DIR/src/public/app
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

View File

@@ -1,7 +0,0 @@
#!/usr/bin/env node
const anonymizationService = require('../src/services/anonymization');
const fs = require('fs');
const path = require('path');
fs.writeFileSync(path.resolve(__dirname, 'tpl', 'anonymize-database.sql'), anonymizationService.getFullAnonymizationScript());

View File

@@ -1,57 +0,0 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=$1
if ! [[ ${VERSION} =~ ^[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}(-.+)?$ ]] ;
then
echo "Version ${VERSION} isn't in format X.Y.Z"
exit 1
fi
VERSION_DATE=$(git log -1 --format=%aI "v${VERSION}" | cut -c -10)
VERSION_COMMIT=$(git rev-list -n 1 "v${VERSION}")
# expecting the directory at a specific path
cd ~/trilium-flathub || exit
if ! git diff-index --quiet HEAD --; then
echo "There are uncommitted changes"
exit 1
fi
BASE_BRANCH=master
if [[ "$VERSION" == *"beta"* ]]; then
BASE_BRANCH=beta
fi
git switch "${BASE_BRANCH}"
git pull
BRANCH=b${VERSION}
git branch "${BRANCH}"
git switch "${BRANCH}"
echo "Updating files with version ${VERSION}, date ${VERSION_DATE} and commit ${VERSION_COMMIT}"
flatpak-node-generator npm ../trilium/package-lock.json
xmlstarlet ed --inplace --update "/component/releases/release/@version" --value "${VERSION}" --update "/component/releases/release/@date" --value "${VERSION_DATE}" ./com.github.zadam.trilium.metainfo.xml
yq --inplace "(.modules[0].sources[0].tag = \"v${VERSION}\") | (.modules[0].sources[0].commit = \"${VERSION_COMMIT}\")" ./com.github.zadam.trilium.yml
git add ./generated-sources.json
git add ./com.github.zadam.trilium.metainfo.xml
git add ./com.github.zadam.trilium.yml
git commit -m "release $VERSION"
git push --set-upstream origin "${BRANCH}"
gh pr create --fill -B "${BASE_BRANCH}"
gh pr merge --auto --merge --delete-branch

View File

@@ -1,17 +0,0 @@
UPDATE etapi_tokens SET tokenHash = 'API token hash value';
UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share');
UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL;
UPDATE note_revisions SET title = 'title';
UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL;
UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN ('inbox', 'disableVersioning', 'calendarRoot', 'archived', 'excludeFromExport', 'disableInclusion', 'appCss', 'appTheme', 'hidePromotedAttributes', 'readOnly', 'autoReadOnlyDisabled', 'cssClass', 'iconClass', 'keyboardShortcut', 'run', 'runOnInstance', 'runAtHour', 'customRequestHandler', 'customResourceProvider', 'widget', 'noteInfoWidgetDisabled', 'linkMapWidgetDisabled', 'noteRevisionsWidgetDisabled', 'whatLinksHereWidgetDisabled', 'similarNotesWidgetDisabled', 'workspace', 'workspaceIconClass', 'workspaceTabBackgroundColor', 'searchHome', 'workspaceInbox', 'workspaceSearchHome', 'sqlConsoleHome', 'datePattern', 'pageSize', 'viewType', 'mapRootNoteId', 'bookmarkFolder', 'sorted', 'top', 'fullContentWidth', 'shareHiddenFromTree', 'shareAlias', 'shareOmitDefaultCss', 'shareRoot', 'shareDescription', 'internalLink', 'imageLink', 'relationMapLink', 'includeMapLink', 'runOnNoteCreation', 'runOnNoteTitleChange', 'runOnNoteContentChange', 'runOnNoteChange', 'runOnChildNoteCreation', 'runOnAttributeCreation', 'runOnAttributeChange', 'template', 'widget', 'renderNote', 'shareCss', 'shareJs', 'shareFavicon');
UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered';
UPDATE options SET value = 'anonymized' WHERE name IN
('documentId', 'documentSecret', 'encryptedDataKey',
'passwordVerificationHash', 'passwordVerificationSalt',
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
AND value != '';
VACUUM;

View File

@@ -1,23 +1,4 @@
@echo off
:: Try to get powershell to launch Trilium since it deals with UTF-8 characters in current path
:: If there's no powershell available, fallback to unicode enabled command interpreter
WHERE powershell.exe > NUL 2>&1
IF %ERRORLEVEL% NEQ 0 GOTO BATCH ELSE GOTO POWERSHELL
:POWERSHELL
powershell -ExecutionPolicy Bypass -NonInteractive -NoLogo "Set-Item -Path Env:NODE_TLS_REJECT_UNAUTHORIZED -Value 0; ./trilium.exe"
GOTO END
:BATCH
:: Make sure we support UTF-8 characters
chcp 65001
:: Get Current Trilium executable directory and compute data directory
SET DIR=%~dp0
set NODE_TLS_REJECT_UNAUTHORIZED=0
cd %DIR%
start trilium.exe
GOTO END
:END

View File

@@ -1,23 +1,4 @@
@echo off
:: Try to get powershell to launch Trilium since it deals with UTF-8 characters in current path
:: If there's no powershell available, fallback to unicode enabled command interpreter
WHERE powershell.exe > NUL 2>&1
IF %ERRORLEVEL% NEQ 0 GOTO BATCH ELSE GOTO POWERSHELL
:POWERSHELL
powershell -ExecutionPolicy Bypass -NonInteractive -NoLogo "Set-Item -Path Env:TRILIUM_DATA_DIR -Value './trilium-data'; ./trilium.exe"
GOTO END
:BATCH
:: Make sure we support UTF-8 characters
chcp 65001
:: Get Current Trilium executable directory and compute data directory
SET DIR=%~dp0
SET TRILIUM_DATA_DIR=%DIR%\trilium-data
cd %DIR%
start trilium.exe
GOTO END
:END
start trilium.exe

View File

@@ -1,23 +1,4 @@
@echo off
:: Try to get powershell to launch Trilium since it deals with UTF-8 characters in current path
:: If there's no powershell available, fallback to unicode enabled command interpreter
WHERE powershell.exe > NUL 2>&1
IF %ERRORLEVEL% NEQ 0 GOTO BATCH ELSE GOTO POWERSHELL
:POWERSHELL
powershell -ExecutionPolicy Bypass -NonInteractive -NoLogo "Set-Item -Path Env:TRILIUM_SAFE_MODE -Value 1; ./trilium.exe --disable-gpu"
GOTO END
:BATCH
:: Make sure we support UTF-8 characters
chcp 65001
:: Get Current Trilium executable directory and compute data directory
SET DIR=%~dp0
SET TRILIUM_SAFE_MODE=1
cd %DIR%
start trilium.exe --disable-gpu
GOTO END
:END
start trilium.exe

View File

@@ -3,5 +3,5 @@
DIR=`dirname "$0"`
export TRILIUM_SAFE_MODE=1
"$DIR/trilium" --disable-gpu
"$DIR/trilium"

View File

@@ -21,9 +21,3 @@ https=false
# path to certificate (run "bash bin/generate-cert.sh" to generate self-signed certificate). Relevant only if https=true
certPath=
keyPath=
# setting to give trust to reverse proxies, a comma-separated list of trusted rev. proxy IPs can be specified (CIDR notation is permitted),
# alternatively 'true' will make use of the leftmost IP in X-Forwarded-For, ultimately an integer can be used to tell about the number of hops between
# Trilium (which is hop 0) and the first trusted rev. proxy.
# once set, expressjs will use the X-Forwarded-For header set by the rev. proxy to determinate the real IPs of clients.
# expressjs shortcuts are supported: loopback(127.0.0.1/8, ::1/128), linklocal(169.254.0.0/16, fe80::/10), uniquelocal(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7)
trustedReverseProxy=false

View File

@@ -1,6 +1,11 @@
- drop branches.utcDateCreated - not used for anything
- drop options.utcDateCreated - not used for anything
- isDeleted = 0 by default
- rename openTabs to openNoteContexts
- migrate black theme to dark theme
- unify readOnly handling to a single attribute:
* readOnly - like now
* readOnly=auto - like without readOnly (used to override inherited readOnly)
* readOnly=never - like autoReadOnlyDisabled
- remove focusOnAttributesKeyboardShortcut
- rename white theme to "light" theme (it's not completely white and matches well to dark theme)

Binary file not shown.

View File

@@ -1 +0,0 @@
module.exports = () => console.log("NOOP, moved to migration 0189");

View File

@@ -10,20 +10,10 @@ CREATE TABLE IF NOT EXISTS "mig_entity_changes" (
`utcDateChanged` TEXT NOT NULL
);
INSERT INTO mig_entity_changes (id, entityName, entityId, hash, isErased, changeId, sourceId, isSynced, utcDateChanged)
SELECT id, entityName, entityId, hash, isErased, '', sourceId, isSynced, utcDateChanged FROM entity_changes;
INSERT INTO mig_entity_changes (entityName, entityId, hash, isErased, changeId, sourceId, isSynced, utcDateChanged)
SELECT entityName, entityId, hash, isErased, '', sourceId, isSynced, utcDateChanged FROM entity_changes;
-- delete duplicates https://github.com/zadam/trilium/issues/2534
DELETE FROM mig_entity_changes WHERE isErased = 0 AND id IN (
SELECT id FROM mig_entity_changes ec
WHERE (
SELECT COUNT(*) FROM mig_entity_changes
WHERE ec.entityName = mig_entity_changes.entityName
AND ec.entityId = mig_entity_changes.entityId
) > 1
);
DROP TABLE entity_changes;
DROP TABLE entity_changes;
ALTER TABLE mig_entity_changes RENAME TO entity_changes;

View File

@@ -1,8 +0,0 @@
UPDATE branches SET branchId = 'hidden' where branchId = (
SELECT branchId FROM branches
WHERE parentNoteId = 'root'
AND noteId = 'hidden'
AND isDeleted = 0
ORDER BY utcDateModified
LIMIT 1
);

View File

@@ -1 +0,0 @@
DELETE FROM options WHERE name = 'username';

View File

@@ -1,15 +0,0 @@
CREATE TABLE IF NOT EXISTS "etapi_tokens"
(
etapiTokenId TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
tokenHash TEXT NOT NULL,
utcDateCreated TEXT NOT NULL,
utcDateModified TEXT NOT NULL,
isDeleted INT NOT NULL DEFAULT 0);
INSERT INTO etapi_tokens (etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified, isDeleted)
SELECT apiTokenId, 'Trilium Sender', token, utcDateCreated, utcDateCreated, isDeleted FROM api_tokens;
DROP TABLE api_tokens;
UPDATE entity_changes SET entityName = 'etapi_tokens' WHERE entityName = 'api_tokens';

View File

@@ -1,10 +0,0 @@
module.exports = () => {
const sql = require('../../src/services/sql');
const crypto = require('crypto');
for (const {etapiTokenId, token} of sql.getRows("SELECT etapiTokenId, tokenHash AS token FROM etapi_tokens")) {
const tokenHash = crypto.createHash('sha256').update(token).digest('base64');
sql.execute(`UPDATE etapi_tokens SET tokenHash = ? WHERE etapiTokenId = ?`, [tokenHash, etapiTokenId]);
}
};

View File

@@ -1,20 +0,0 @@
DROP TABLE entity_changes;
-- not preserving the data because of https://github.com/zadam/trilium/issues/3447
CREATE TABLE IF NOT EXISTS "entity_changes" (
`id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
`entityName` TEXT NOT NULL,
`entityId` TEXT NOT NULL,
`hash` TEXT NOT NULL,
`isErased` INT NOT NULL,
`changeId` TEXT NOT NULL,
`componentId` TEXT NOT NULL,
`instanceId` TEXT NOT NULL,
`isSynced` INTEGER NOT NULL,
`utcDateChanged` TEXT NOT NULL
);
CREATE UNIQUE INDEX `IDX_entityChanges_entityName_entityId` ON "entity_changes" (
`entityName`,
`entityId`
);

View File

@@ -1 +0,0 @@
CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`);

View File

@@ -1,2 +0,0 @@
-- removing potential remnants of recent notes in entity changes, see https://github.com/zadam/trilium/issues/2842
DELETE FROM entity_changes WHERE entityName = 'recent_notes';

View File

@@ -1,2 +0,0 @@
UPDATE attributes SET value = replace(value, 'setLabelValue', 'updateLabelValue') WHERE name = 'action' AND type = 'label';
UPDATE attributes SET value = replace(value, 'setRelationTarget', 'updateRelationTarget') WHERE name = 'action' AND type = 'label';

View File

@@ -1 +0,0 @@
module.exports = () => console.log("NOOP, increased because of protected notes IV change");

View File

@@ -1,6 +0,0 @@
UPDATE branches SET branchId = '_hidden__search' WHERE parentNoteId = 'hidden' AND noteId = 'search' AND isDeleted = 0;
UPDATE branches SET branchId = 'root__globalNoteMap' WHERE parentNoteId = 'singles' AND noteId = 'globalnotemap' AND isDeleted = 0;
UPDATE branches SET branchId = '_hidden__sqlConsole' WHERE parentNoteId = 'hidden' AND noteId = 'sqlconsole' AND isDeleted = 0;
UPDATE branches SET branchId = 'root__hidden' WHERE parentNoteId = 'root' AND noteId = 'hidden' AND isDeleted = 0;
UPDATE branches SET branchId = '_hidden__bulkAction' WHERE parentNoteId = 'hidden' AND noteId = 'bulkaction' AND isDeleted = 0;
UPDATE branches SET branchId = '_hidden__share' WHERE parentNoteId = 'root' AND noteId = 'share' AND isDeleted = 0;

View File

@@ -1,53 +0,0 @@
UPDATE notes SET noteId = '_globalNoteMap', title = 'Note Map' WHERE noteId = 'globalnotemap';
UPDATE note_contents SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap';
UPDATE note_revisions SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap';
UPDATE branches SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap';
UPDATE branches SET parentNoteId = '_globalNoteMap' WHERE parentNoteId = 'globalnotemap';
UPDATE attributes SET noteId = '_globalNoteMap' WHERE noteId = 'globalnotemap';
UPDATE attributes SET value = '_globalNoteMap' WHERE type = 'relation' AND value = 'globalnotemap';
UPDATE entity_changes SET entityId = '_globalNoteMap' WHERE entityId = 'globalnotemap';
UPDATE notes SET noteId = '_bulkAction', title = 'Bulk Action' WHERE noteId = 'bulkaction';
UPDATE note_contents SET noteId = '_bulkAction' WHERE noteId = 'bulkaction';
UPDATE note_revisions SET noteId = '_bulkAction' WHERE noteId = 'bulkaction';
UPDATE branches SET parentNoteId = '_bulkAction' WHERE parentNoteId = 'bulkaction';
UPDATE branches SET noteId = '_bulkAction' WHERE noteId = 'bulkaction';
UPDATE attributes SET noteId = '_bulkAction' WHERE noteId = 'bulkaction';
UPDATE attributes SET value = '_bulkAction' WHERE type = 'relation' AND value = 'bulkaction';
UPDATE entity_changes SET entityId = '_bulkAction' WHERE entityId = 'bulkaction';
UPDATE notes SET noteId = '_sqlConsole', title = 'SQL Console History' WHERE noteId = 'sqlconsole';
UPDATE note_contents SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole';
UPDATE note_revisions SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole';
UPDATE branches SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole';
UPDATE branches SET parentNoteId = '_sqlConsole' WHERE parentNoteId = 'sqlconsole';
UPDATE attributes SET noteId = '_sqlConsole' WHERE noteId = 'sqlconsole';
UPDATE attributes SET value = '_sqlConsole' WHERE type = 'relation' AND value = 'sqlconsole';
UPDATE entity_changes SET entityId = '_sqlConsole' WHERE entityId = 'sqlconsole';
UPDATE notes SET noteId = '_hidden', title = 'Hidden Notes' WHERE noteId = 'hidden';
UPDATE note_contents SET noteId = '_hidden' WHERE noteId = 'hidden';
UPDATE note_revisions SET noteId = '_hidden' WHERE noteId = 'hidden';
UPDATE branches SET noteId = '_hidden', prefix = NULL WHERE noteId = 'hidden';
UPDATE branches SET parentNoteId = '_hidden' WHERE parentNoteId = 'hidden';
UPDATE attributes SET noteId = '_hidden' WHERE noteId = 'hidden';
UPDATE attributes SET value = '_hidden' WHERE type = 'relation' AND value = 'hidden';
UPDATE entity_changes SET entityId = '_hidden' WHERE entityId = 'hidden';
UPDATE notes SET noteId = '_search', title = 'Search History' WHERE noteId = 'search';
UPDATE note_contents SET noteId = '_search' WHERE noteId = 'search';
UPDATE note_revisions SET noteId = '_search' WHERE noteId = 'search';
UPDATE branches SET noteId = '_search' WHERE noteId = 'search';
UPDATE branches SET parentNoteId = '_search' WHERE parentNoteId = 'search';
UPDATE attributes SET noteId = '_search' WHERE noteId = 'search';
UPDATE attributes SET value = '_search' WHERE type = 'relation' AND value = 'search';
UPDATE entity_changes SET entityId = '_search' WHERE entityId = 'search';
UPDATE notes SET noteId = '_share', title = 'Shared Notes' WHERE noteId = 'share';
UPDATE note_contents SET noteId = '_share' WHERE noteId = 'share';
UPDATE note_revisions SET noteId = '_share' WHERE noteId = 'share';
UPDATE branches SET noteId = '_share' WHERE noteId = 'share';
UPDATE branches SET parentNoteId = '_share' WHERE parentNoteId = 'share';
UPDATE attributes SET noteId = '_share' WHERE noteId = 'share';
UPDATE attributes SET value = '_share' WHERE type = 'relation' AND value = 'share';
UPDATE entity_changes SET entityId = '_share' WHERE entityId = 'share';

View File

@@ -1,12 +0,0 @@
module.exports = () => {
const hiddenSubtreeService = require('../../src/services/hidden_subtree');
const cls = require("../../src/services/cls");
const beccaLoader = require("../../src/becca/becca_loader");
cls.init(() => {
beccaLoader.load();
// make sure the hidden subtree exists since the subsequent migrations we will move some existing notes into it (share...)
// in previous releases hidden subtree was created lazily
hiddenSubtreeService.checkHiddenSubtree();
});
};

View File

@@ -1,2 +0,0 @@
DELETE FROM branches WHERE noteId = '_share' AND parentNoteId != 'root' AND parentNoteId != '_hidden'; -- delete all other branches of _share if any
UPDATE branches SET parentNoteId = '_hidden' WHERE noteId = '_share';

View File

@@ -1,2 +0,0 @@
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';

View File

@@ -1,6 +0,0 @@
DELETE FROM branches WHERE noteId = 'singles';
DELETE FROM notes WHERE noteId = 'singles';
DELETE FROM note_contents WHERE noteId = 'singles';
DELETE FROM note_revisions WHERE noteId = 'singles';
DELETE FROM attributes WHERE noteId = 'singles';
DELETE FROM entity_changes WHERE entityId = 'singles';

View File

@@ -1,21 +0,0 @@
module.exports = () => {
const cls = require("../../src/services/cls");
const cloningService = require("../../src/services/cloning");
const beccaLoader = require("../../src/becca/becca_loader");
const becca = require("../../src/becca/becca");
cls.init(() => {
beccaLoader.load();
for (const attr of becca.findAttributes('label','bookmarked')) {
cloningService.toggleNoteInParent(true, attr.noteId, '_lbBookmarks');
attr.markAsDeleted("0204__migrate_bookmarks_to_clones");
}
// bookmarkFolder used to work in 0.57 without the bookmarked label
for (const attr of becca.findAttributes('label','bookmarkFolder')) {
cloningService.toggleNoteInParent(true, attr.noteId, '_lbBookmarks');
}
});
};

View File

@@ -1,3 +0,0 @@
UPDATE notes SET type = 'relationMap' WHERE type = 'relation-map';
UPDATE notes SET type = 'noteMap' WHERE type = 'note-map';
UPDATE notes SET type = 'webView' WHERE type = 'web-view';

View File

@@ -1,33 +0,0 @@
// the history was previously not exposed and the fact they were not cleaned up is rather a side-effect than an intention
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();
// deleting just branches because they might be cloned (and therefore saved) also outside of the hidden subtree
const searchRoot = becca.getNote('_search');
for (const searchBranch of searchRoot.getChildBranches()) {
const searchNote = searchBranch.getNote();
if (searchNote.type === 'search') {
searchBranch.deleteBranch('0206__delete_search_and_sql_console_history');
}
}
const sqlConsoleRoot = becca.getNote('_sqlConsole');
for (const sqlConsoleBranch of sqlConsoleRoot.getChildBranches()) {
const sqlConsoleNote = sqlConsoleBranch.getNote();
if (sqlConsoleNote.type === 'code' && sqlConsoleNote.mime === 'text/x-sqlite;schema=trilium') {
sqlConsoleBranch.deleteBranch('0206__delete_search_and_sql_console_history');
}
}
});
};

View File

@@ -1,2 +0,0 @@
UPDATE notes SET title = 'SQL Console History' WHERE noteId = '_sqlConsole';
UPDATE notes SET title = 'Search History' WHERE noteId = '_search';

View File

@@ -1,13 +0,0 @@
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();
for (const label of becca.getNote('_hidden').getLabels('archived')) {
label.markAsDeleted('0208__remove_archived_from_hidden');
}
});
};

View File

@@ -1,5 +0,0 @@
UPDATE attributes SET name = 'workspaceInbox' WHERE type = 'label' AND name = 'hoistedInbox';
UPDATE entity_changes SET entityId = 'workspaceInbox' WHERE entityName = 'attributes' AND entityId = 'hoistedInbox';
UPDATE attributes SET name = 'workspaceSearchHome' WHERE type = 'label' AND name = 'hoistedSearchHome';
UPDATE entity_changes SET entityId = 'workspaceSearchHome' WHERE entityName = 'attributes' AND entityId = 'hoistedSearchHome';

View File

@@ -1,24 +0,0 @@
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}`);
}
});
};

View File

@@ -1,12 +0,0 @@
-- 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;

View File

@@ -1,21 +0,0 @@
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");
}
}
}
});
};

View File

@@ -5,18 +5,15 @@ CREATE TABLE IF NOT EXISTS "entity_changes" (
`hash` TEXT NOT NULL,
`isErased` INT NOT NULL,
`changeId` TEXT NOT NULL,
`componentId` TEXT NOT NULL,
`instanceId` TEXT NOT NULL,
`sourceId` TEXT NOT NULL,
`isSynced` INTEGER NOT NULL,
`utcDateChanged` TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS "etapi_tokens"
CREATE TABLE IF NOT EXISTS "api_tokens"
(
etapiTokenId TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
tokenHash TEXT NOT NULL,
apiTokenId TEXT PRIMARY KEY NOT NULL,
token TEXT NOT NULL,
utcDateCreated TEXT NOT NULL,
utcDateModified TEXT NOT NULL,
isDeleted INT NOT NULL DEFAULT 0);
CREATE TABLE IF NOT EXISTS "branches" (
`branchId` TEXT NOT NULL,
@@ -53,7 +50,7 @@ CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIM
`noteId` TEXT NOT NULL,
type TEXT DEFAULT '' NOT NULL,
mime TEXT DEFAULT '' NOT NULL,
`title` TEXT NOT NULL,
`title` TEXT,
`isProtected` INT NOT NULL DEFAULT 0,
`utcDateLastEdited` TEXT NOT NULL,
`utcDateCreated` TEXT NOT NULL,
@@ -66,7 +63,7 @@ CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT N
CREATE TABLE IF NOT EXISTS "options"
(
name TEXT not null PRIMARY KEY,
value TEXT not null,
value TEXT,
isSynced INTEGER default 0 not null,
utcDateModified TEXT NOT NULL
);
@@ -99,7 +96,6 @@ CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCr
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
CREATE INDEX `IDX_entity_changes_changeId` ON `entity_changes` (`changeId`);
CREATE INDEX IDX_attributes_name_value
on attributes (name, value);
CREATE INDEX IDX_attributes_noteId_index

View File

@@ -1,14 +1,17 @@
version: '2.1'
services:
trilium:
build:
context: .
image: zadam/trilium
restart: always
environment:
- TRILIUM_DATA_DIR=/home/node/trilium-data
- TRILIUM_DATA_DIR=/data
ports:
- "8080:8080"
volumes:
- trilium:/home/node/trilium-data
- trilium:/data
volumes:
trilium:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,378 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: ApiToken</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: ApiToken</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>ApiToken<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description">ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender.</div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="ApiToken"><span class="type-signature"></span>new ApiToken<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line9">line 9</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Members</h3>
<h4 class="name" id="apiTokenId"><span class="type-signature"></span>apiTokenId<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line18">line 18</a>
</li></ul></dd>
</dl>
<h4 class="name" id="token"><span class="type-signature"></span>token<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line20">line 20</a>
</li></ul></dd>
</dl>
<h4 class="name" id="utcDateCreated"><span class="type-signature"></span>utcDateCreated<span class="type-signature"> :string</span></h4>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">string</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_api_token.js.html">becca/entities/api_token.js</a>, <a href="becca_entities_api_token.js.html#line22">line 22</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -93,7 +93,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line11">line 11</a>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line9">line 9</a>
</li></ul></dd>
@@ -127,17 +127,6 @@
</div>
<h3 class="subsection-title">Extends</h3>
<ul>
<li><a href="AbstractEntity.html">AbstractEntity</a></li>
</ul>
@@ -154,69 +143,6 @@
<h4 class="name" id="becca"><span class="type-signature">(protected) </span>becca<span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#becca">AbstractEntity#becca</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line50">line 50</a>
</li></ul></dd>
</dl>
<h4 class="name" id="isSynced"><span class="type-signature"></span>isSynced<span class="type-signature"> :boolean</span></h4>
@@ -267,7 +193,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line24">line 24</a>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line22">line 22</a>
</li></ul></dd>
@@ -335,7 +261,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line20">line 20</a>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line18">line 18</a>
</li></ul></dd>
@@ -403,7 +329,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line26">line 26</a>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line24">line 24</a>
</li></ul></dd>
@@ -471,7 +397,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line22">line 22</a>
<a href="becca_entities_option.js.html">becca/entities/option.js</a>, <a href="becca_entities_option.js.html#line20">line 20</a>
</li></ul></dd>
@@ -491,814 +417,6 @@
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id="addEntityChange"><span class="type-signature">(protected) </span>addEntityChange<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#addEntityChange">AbstractEntity#addEntityChange</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line59">line 59</a>
</li></ul></dd>
</dl>
<h4 class="name" id="beforeSaving"><span class="type-signature">(protected) </span>beforeSaving<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#beforeSaving">AbstractEntity#beforeSaving</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line18">line 18</a>
</li></ul></dd>
</dl>
<h4 class="name" id="generateHash"><span class="type-signature">(protected) </span>generateHash<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#generateHash">AbstractEntity#generateHash</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line30">line 30</a>
</li></ul></dd>
</dl>
<h4 class="name" id="generateIdIfNecessary"><span class="type-signature">(protected) </span>generateIdIfNecessary<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#generateIdIfNecessary">AbstractEntity#generateIdIfNecessary</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line23">line 23</a>
</li></ul></dd>
</dl>
<h4 class="name" id="getPojoToSave"><span class="type-signature">(protected) </span>getPojoToSave<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#getPojoToSave">AbstractEntity#getPojoToSave</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line71">line 71</a>
</li></ul></dd>
</dl>
<h4 class="name" id="getUtcDateChanged"><span class="type-signature">(protected) </span>getUtcDateChanged<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#getUtcDateChanged">AbstractEntity#getUtcDateChanged</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line45">line 45</a>
</li></ul></dd>
</dl>
<h4 class="name" id="markAsDeleted"><span class="type-signature"></span>markAsDeleted<span class="signature">(deleteId<span class="signature-attributes">opt</span>)</span><span class="type-signature"></span></h4>
<div class="description">
Mark the entity as (soft) deleted. It will be completely erased later.
This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
</div>
<h5>Parameters:</h5>
<table class="params">
<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>deleteId</code></td>
<td class="type">
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
null
</td>
<td class="description last"></td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#markAsDeleted">AbstractEntity#markAsDeleted</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line125">line 125</a>
</li></ul></dd>
</dl>
<h4 class="name" id="save"><span class="type-signature"></span>save<span class="signature">()</span><span class="type-signature"> &rarr; {<a href="AbstractEntity.html">AbstractEntity</a>}</span></h4>
<div class="description">
Saves entity - executes SQL, but doesn't commit the transaction on its own
</div>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#save">AbstractEntity#save</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line80">line 80</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type"><a href="AbstractEntity.html">AbstractEntity</a></span>
</dd>
</dl>
@@ -1313,13 +431,13 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -93,7 +93,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line11">line 11</a>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line9">line 9</a>
</li></ul></dd>
@@ -127,17 +127,6 @@
</div>
<h3 class="subsection-title">Extends</h3>
<ul>
<li><a href="AbstractEntity.html">AbstractEntity</a></li>
</ul>
@@ -154,69 +143,6 @@
<h4 class="name" id="becca"><span class="type-signature">(protected) </span>becca<span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#becca">AbstractEntity#becca</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line50">line 50</a>
</li></ul></dd>
</dl>
<h4 class="name" id="noteId"><span class="type-signature"></span>noteId<span class="type-signature"> :string</span></h4>
@@ -267,7 +193,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line19">line 19</a>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line17">line 17</a>
</li></ul></dd>
@@ -335,7 +261,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line21">line 21</a>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line19">line 19</a>
</li></ul></dd>
@@ -403,7 +329,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line23">line 23</a>
<a href="becca_entities_recent_note.js.html">becca/entities/recent_note.js</a>, <a href="becca_entities_recent_note.js.html#line21">line 21</a>
</li></ul></dd>
@@ -423,814 +349,6 @@
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id="addEntityChange"><span class="type-signature">(protected) </span>addEntityChange<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#addEntityChange">AbstractEntity#addEntityChange</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line59">line 59</a>
</li></ul></dd>
</dl>
<h4 class="name" id="beforeSaving"><span class="type-signature">(protected) </span>beforeSaving<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#beforeSaving">AbstractEntity#beforeSaving</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line18">line 18</a>
</li></ul></dd>
</dl>
<h4 class="name" id="generateHash"><span class="type-signature">(protected) </span>generateHash<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#generateHash">AbstractEntity#generateHash</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line30">line 30</a>
</li></ul></dd>
</dl>
<h4 class="name" id="generateIdIfNecessary"><span class="type-signature">(protected) </span>generateIdIfNecessary<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#generateIdIfNecessary">AbstractEntity#generateIdIfNecessary</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line23">line 23</a>
</li></ul></dd>
</dl>
<h4 class="name" id="getPojoToSave"><span class="type-signature">(protected) </span>getPojoToSave<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#getPojoToSave">AbstractEntity#getPojoToSave</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line71">line 71</a>
</li></ul></dd>
</dl>
<h4 class="name" id="getUtcDateChanged"><span class="type-signature">(protected) </span>getUtcDateChanged<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#getUtcDateChanged">AbstractEntity#getUtcDateChanged</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line45">line 45</a>
</li></ul></dd>
</dl>
<h4 class="name" id="markAsDeleted"><span class="type-signature"></span>markAsDeleted<span class="signature">(deleteId<span class="signature-attributes">opt</span>)</span><span class="type-signature"></span></h4>
<div class="description">
Mark the entity as (soft) deleted. It will be completely erased later.
This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
</div>
<h5>Parameters:</h5>
<table class="params">
<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>deleteId</code></td>
<td class="type">
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
null
</td>
<td class="description last"></td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#markAsDeleted">AbstractEntity#markAsDeleted</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line125">line 125</a>
</li></ul></dd>
</dl>
<h4 class="name" id="save"><span class="type-signature"></span>save<span class="signature">()</span><span class="type-signature"> &rarr; {<a href="AbstractEntity.html">AbstractEntity</a>}</span></h4>
<div class="description">
Saves entity - executes SQL, but doesn't commit the transaction on its own
</div>
<dl class="details">
<dt class="tag-overrides">Overrides:</dt>
<dd class="tag-overrides"><ul class="dummy"><li>
<a href="AbstractEntity.html#save">AbstractEntity#save</a>
</li></ul></dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="becca_entities_abstract_entity.js.html">becca/entities/abstract_entity.js</a>, <a href="becca_entities_abstract_entity.js.html#line80">line 80</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type"><a href="AbstractEntity.html">AbstractEntity</a></span>
</dd>
</dl>
@@ -1245,13 +363,13 @@ This is a low level method, for notes and branches use `note.deleteNote()` and '
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1,218 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: becca/entities/abstract_entity.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: becca/entities/abstract_entity.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const utils = require('../../services/utils');
const sql = require('../../services/sql');
const entityChangesService = require('../../services/entity_changes');
const eventService = require("../../services/events");
const dateUtils = require("../../services/date_utils");
const cls = require("../../services/cls");
const log = require("../../services/log");
let becca = null;
/**
* Base class for all backend entities.
*/
class AbstractEntity {
/** @protected */
beforeSaving() {
this.generateIdIfNecessary();
}
/** @protected */
generateIdIfNecessary() {
if (!this[this.constructor.primaryKeyName]) {
this[this.constructor.primaryKeyName] = utils.newEntityId();
}
}
/** @protected */
generateHash(isDeleted = false) {
let contentToHash = "";
for (const propertyName of this.constructor.hashedProperties) {
contentToHash += `|${this[propertyName]}`;
}
if (isDeleted) {
contentToHash += "|deleted";
}
return utils.hash(contentToHash).substr(0, 10);
}
/** @protected */
getUtcDateChanged() {
return this.utcDateModified || this.utcDateCreated;
}
/** @protected */
get becca() {
if (!becca) {
becca = require('../becca');
}
return becca;
}
/** @protected */
addEntityChange(isDeleted = false) {
entityChangesService.addEntityChange({
entityName: this.constructor.entityName,
entityId: this[this.constructor.primaryKeyName],
hash: this.generateHash(isDeleted),
isErased: false,
utcDateChanged: this.getUtcDateChanged(),
isSynced: this.constructor.entityName !== 'options' || !!this.isSynced
});
}
/** @protected */
getPojoToSave() {
return this.getPojo();
}
/**
* Saves entity - executes SQL, but doesn't commit the transaction on its own
*
* @returns {AbstractEntity}
*/
save() {
const entityName = this.constructor.entityName;
const primaryKeyName = this.constructor.primaryKeyName;
const isNewEntity = !this[primaryKeyName];
if (this.beforeSaving) {
this.beforeSaving();
}
const pojo = this.getPojoToSave();
sql.transactional(() => {
sql.upsert(entityName, primaryKeyName, pojo);
if (entityName === 'recent_notes') {
return;
}
this.addEntityChange(false);
if (!cls.isEntityEventsDisabled()) {
const eventPayload = {
entityName,
entity: this
};
if (isNewEntity) {
eventService.emit(eventService.ENTITY_CREATED, eventPayload);
}
eventService.emit(eventService.ENTITY_CHANGED, eventPayload);
}
});
return this;
}
/**
* Mark the entity as (soft) deleted. It will be completely erased later.
*
* This is a low level method, for notes and branches use `note.deleteNote()` and 'branch.deleteBranch()` instead.
*
* @param [deleteId=null]
*/
markAsDeleted(deleteId = null) {
const entityId = this[this.constructor.primaryKeyName];
const entityName = this.constructor.entityName;
this.utcDateModified = dateUtils.utcNowDateTime();
sql.execute(`UPDATE ${entityName} SET isDeleted = 1, deleteId = ?, utcDateModified = ?
WHERE ${this.constructor.primaryKeyName} = ?`,
[deleteId, this.utcDateModified, entityId]);
if (this.dateModified) {
this.dateModified = dateUtils.localNowDateTime();
sql.execute(`UPDATE ${entityName} SET dateModified = ? WHERE ${this.constructor.primaryKeyName} = ?`,
[this.dateModified, entityId]);
}
log.info(`Marking ${entityName} ${entityId} as deleted`);
this.addEntityChange(true);
eventService.emit(eventService.ENTITY_DELETED, { entityName, entityId, entity: this });
}
markAsDeletedSimple() {
const entityId = this[this.constructor.primaryKeyName];
const entityName = this.constructor.entityName;
this.utcDateModified = dateUtils.utcNowDateTime();
sql.execute(`UPDATE ${entityName} SET isDeleted = 1, utcDateModified = ?
WHERE ${this.constructor.primaryKeyName} = ?`,
[this.utcDateModified, entityId]);
log.info(`Marking ${entityName} ${entityId} as deleted`);
this.addEntityChange(true);
eventService.emit(eventService.ENTITY_DELETED, { entityName, entityId, entity: this });
}
}
module.exports = AbstractEntity;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: becca/entities/api_token.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: becca/entities/api_token.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* ApiToken is an entity representing token used to authenticate against Trilium API from client applications. Currently used only by Trilium Sender.
*/
class ApiToken extends AbstractEntity {
static get entityName() { return "api_tokens"; }
static get primaryKeyName() { return "apiTokenId"; }
static get hashedProperties() { return ["apiTokenId", "token", "utcDateCreated"]; }
constructor(row) {
super();
/** @type {string} */
this.apiTokenId = row.apiTokenId;
/** @type {string} */
this.token = row.token;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
}
getPojo() {
return {
apiTokenId: this.apiTokenId,
token: this.token,
utcDateCreated: this.utcDateCreated
}
}
}
module.exports = ApiToken;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -28,18 +28,15 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const sql = require("../../services/sql");
const dateUtils = require("../../services/date_utils");
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
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)
* and relation (representing named relationship between source and target note)
*
* @extends AbstractEntity
*/
class Attribute extends AbstractEntity {
static get entityName() { return "attributes"; }
@@ -82,7 +79,7 @@ class Attribute extends AbstractEntity {
/** @type {int} */
this.position = position;
/** @type {string} */
this.value = value || "";
this.value = value;
/** @type {boolean} */
this.isInheritable = !!isInheritable;
/** @type {string} */
@@ -114,20 +111,6 @@ class Attribute extends AbstractEntity {
}
}
validate() {
if (!["label", "relation"].includes(this.type)) {
throw new Error(`Invalid attribute type '${this.type}' in attribute '${this.attributeId}' of note '${this.noteId}'`);
}
if (!this.name?.trim()) {
throw new Error(`Invalid empty name in attribute '${this.attributeId}' of note '${this.noteId}'`);
}
if (this.type === 'relation' &amp;&amp; !(this.value in this.becca.notes)) {
throw new Error(`Cannot save relation '${this.name}' of note '${this.noteId}' since it target not existing note '${this.value}'.`);
}
}
get isAffectingSubtree() {
return this.isInheritable
|| (this.type === 'relation' &amp;&amp; this.name === 'template');
@@ -155,13 +138,7 @@ class Attribute extends AbstractEntity {
* @returns {Note|null}
*/
getNote() {
const note = this.becca.getNote(this.noteId);
if (!note) {
throw new Error(`Note '${this.noteId}' of attribute '${this.attributeId}', type '${this.type}', name '${this.name}' does not exist.`);
}
return note;
return this.becca.getNote(this.noteId);
}
/**
@@ -205,11 +182,11 @@ class Attribute extends AbstractEntity {
}
beforeSaving() {
this.validate();
this.name = sanitizeAttributeName(this.name);
if (!this.value) {
if (this.type === 'relation') {
throw new Error(`Cannot save relation ${this.name} since it does not target any note.`);
}
// null value isn't allowed
this.value = "";
}
@@ -268,13 +245,13 @@ module.exports = Attribute;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -28,22 +28,14 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const Note = require('./note');
const AbstractEntity = require("./abstract_entity");
const dateUtils = require("../../services/date_utils");
const utils = require("../../services/utils");
const TaskContext = require("../../services/task_context");
const cls = require("../../services/cls");
const log = require("../../services/log");
const Note = require('./note.js');
const AbstractEntity = require("./abstract_entity.js");
const sql = require("../../services/sql.js");
const dateUtils = require("../../services/date_utils.js");
/**
* 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 {
static get entityName() { return "branches"; }
@@ -94,37 +86,33 @@ class Branch extends AbstractEntity {
}
init() {
if (this.branchId) {
this.becca.branches[this.branchId] = this;
}
this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this;
const childNote = this.childNote;
if (!childNote.parentBranches.includes(this)) {
childNote.parentBranches.push(this);
}
if (this.branchId === 'root') {
return;
}
const childNote = this.childNote;
const parentNote = this.parentNote;
if (!childNote.parents.includes(parentNote)) {
childNote.parents.push(parentNote);
}
if (!childNote.parentBranches.includes(this)) {
childNote.parentBranches.push(this);
}
if (!parentNote.children.includes(childNote)) {
parentNote.children.push(childNote);
}
this.becca.branches[this.branchId] = this;
this.becca.childParentToBranch[`${this.noteId}-${this.parentNoteId}`] = this;
}
/** @returns {Note} */
get childNote() {
if (!(this.noteId in this.becca.notes)) {
// entities can come out of order in sync/import, create skeleton which will be filled later
// entities can come out of order in sync, create skeleton which will be filled later
this.becca.addNote(this.noteId, new Note({noteId: this.noteId}));
}
@@ -135,10 +123,10 @@ class Branch extends AbstractEntity {
return this.childNote;
}
/** @returns {Note|undefined} - root branch will have undefined parent, all other branches have to have a parent note */
/** @returns {Note} */
get parentNote() {
if (!(this.parentNoteId in this.becca.notes) &amp;&amp; this.parentNoteId !== 'none') {
// entities can come out of order in sync/import, create skeleton which will be filled later
if (!(this.parentNoteId in this.becca.notes)) {
// entities can come out of order in sync, create skeleton which will be filled later
this.becca.addNote(this.parentNoteId, new Note({noteId: this.parentNoteId}));
}
@@ -149,104 +137,11 @@ class Branch extends AbstractEntity {
return !(this.branchId in this.becca.branches);
}
/**
* Branch is weak when its existence should not hinder deletion of its note.
* As a result, note with only weak branches should be immediately deleted.
* An example is shared or bookmarked clones - they are created automatically and exist for technical reasons,
* not as user-intended actions. From user perspective, they don't count as real clones and for the purpose
* of deletion should not act as a clone.
*
* @returns {boolean}
*/
get isWeak() {
return ['_share', '_lbBookmarks'].includes(this.parentNoteId);
}
/**
* Delete a branch. If this is a last note's branch, delete the note as well.
*
* @param {string} [deleteId] - optional delete identified
* @param {TaskContext} [taskContext]
*
* @return {boolean} - true if note has been deleted, false otherwise
*/
deleteBranch(deleteId, taskContext) {
if (!deleteId) {
deleteId = utils.randomString(10);
}
if (!taskContext) {
taskContext = new TaskContext('no-progress-reporting');
}
taskContext.increaseProgressCount();
const note = this.getNote();
if (!taskContext.noteDeletionHandlerTriggered) {
const parentBranches = note.getParentBranches();
if (parentBranches.length === 1 &amp;&amp; parentBranches[0] === this) {
// needs to be run before branches and attributes are deleted and thus attached relations disappear
const handlers = require("../../services/handlers");
handlers.runAttachedRelations(note, 'runOnNoteDeletion', note);
}
}
if (this.branchId === 'root'
|| this.noteId === 'root'
|| this.noteId === cls.getHoistedNoteId()) {
throw new Error("Can't delete root or hoisted branch/note");
}
this.markAsDeleted(deleteId);
const notDeletedBranches = note.getStrongParentBranches();
if (notDeletedBranches.length === 0) {
for (const weakBranch of note.getParentBranches()) {
weakBranch.markAsDeleted(deleteId);
}
for (const childBranch of note.getChildBranches()) {
childBranch.deleteBranch(deleteId, taskContext);
}
// first delete children and then parent - this will show up better in recent changes
log.info(`Deleting note ${note.noteId}`);
this.becca.notes[note.noteId].isBeingDeleted = true;
for (const attribute of note.getOwnedAttributes()) {
attribute.markAsDeleted(deleteId);
}
for (const relation of note.getTargetRelations()) {
relation.markAsDeleted(deleteId);
}
note.markAsDeleted(deleteId);
return true;
}
else {
return false;
}
}
beforeSaving() {
if (this.notePosition === undefined || this.notePosition === null) {
let maxNotePos = 0;
for (const childBranch of this.parentNote.getChildBranches()) {
if (maxNotePos &lt; childBranch.notePosition &amp;&amp; childBranch.noteId !== '_hidden') {
maxNotePos = childBranch.notePosition;
}
}
this.notePosition = maxNotePos + 10;
// TODO finding new position can be refactored into becca
const maxNotePos = sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 10;
}
if (!this.isExpanded) {
@@ -269,7 +164,9 @@ class Branch extends AbstractEntity {
notePosition: this.notePosition,
isExpanded: this.isExpanded,
isDeleted: false,
utcDateModified: this.utcDateModified
utcDateModified: this.utcDateModified,
// not used for anything, will be later dropped
utcDateCreated: dateUtils.utcNowDateTime()
};
}
@@ -295,13 +192,13 @@ module.exports = Branch;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1,129 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: becca/entities/etapi_token.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: becca/entities/etapi_token.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
/**
* EtapiToken is an entity representing token used to authenticate against Trilium REST API from client applications.
* Used by:
* - Trilium Sender
* - ETAPI clients
*
* The format user is presented with is "&lt;etapiTokenId>_&lt;tokenHash>". This is also called "authToken" to distinguish it
* from tokenHash and token.
*
* @extends AbstractEntity
*/
class EtapiToken extends AbstractEntity {
static get entityName() { return "etapi_tokens"; }
static get primaryKeyName() { return "etapiTokenId"; }
static get hashedProperties() { return ["etapiTokenId", "name", "tokenHash", "utcDateCreated", "utcDateModified", "isDeleted"]; }
constructor(row) {
super();
if (!row) {
return;
}
this.updateFromRow(row);
this.init();
}
updateFromRow(row) {
/** @type {string} */
this.etapiTokenId = row.etapiTokenId;
/** @type {string} */
this.name = row.name;
/** @type {string} */
this.tokenHash = row.tokenHash;
/** @type {string} */
this.utcDateCreated = row.utcDateCreated || dateUtils.utcNowDateTime();
/** @type {string} */
this.utcDateModified = row.utcDateModified || this.utcDateCreated;
/** @type {boolean} */
this.isDeleted = !!row.isDeleted;
if (this.etapiTokenId) {
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
init() {
if (this.etapiTokenId) {
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
getPojo() {
return {
etapiTokenId: this.etapiTokenId,
name: this.name,
tokenHash: this.tokenHash,
utcDateCreated: this.utcDateCreated,
utcDateModified: this.utcDateModified,
isDeleted: this.isDeleted
}
}
beforeSaving() {
this.utcDateModified = dateUtils.utcNowDateTime();
super.beforeSaving();
this.becca.etapiTokens[this.etapiTokenId] = this;
}
}
module.exports = EtapiToken;
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -34,20 +34,14 @@ const sql = require('../../services/sql');
const utils = require('../../services/utils');
const dateUtils = require('../../services/date_utils');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity");
const NoteRevision = require("./note_revision");
const TaskContext = require("../../services/task_context");
const dayjs = require("dayjs");
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc)
const AbstractEntity = require("./abstract_entity.js");
const NoteRevision = require("./note_revision.js");
const LABEL = 'label';
const RELATION = 'relation';
/**
* Trilium's main entity which can represent text note, image, code note, file attachment etc.
*
* @extends AbstractEntity
*/
class Note extends AbstractEntity {
static get entityName() { return "notes"; }
@@ -100,8 +94,6 @@ class Note extends AbstractEntity {
this.utcDateCreated = utcDateCreated || dateUtils.utcNowDateTime();
/** @type {string} */
this.utcDateModified = utcDateModified;
/** @type {boolean} - set during the deletion operation, before it is completed (removed from becca completely) */
this.isBeingDeleted = false;
// ------ Derived attributes ------
@@ -117,17 +109,13 @@ class Note extends AbstractEntity {
}
init() {
/** @type {Branch[]}
* @private */
/** @type {Branch[]} */
this.parentBranches = [];
/** @type {Note[]}
* @private */
/** @type {Note[]} */
this.parents = [];
/** @type {Note[]}
* @private*/
/** @type {Note[]} */
this.children = [];
/** @type {Attribute[]}
* @private */
/** @type {Attribute[]} */
this.ownedAttributes = [];
/** @type {Attribute[]|null}
@@ -137,8 +125,7 @@ class Note extends AbstractEntity {
* @private*/
this.inheritableAttributeCache = null;
/** @type {Attribute[]}
* @private*/
/** @type {Attribute[]} */
this.targetRelations = [];
this.becca.addNote(this.noteId, this);
@@ -152,19 +139,16 @@ class Note extends AbstractEntity {
/**
* size of the content in bytes
* @type {int|null}
* @private
*/
this.contentSize = null;
/**
* size of the content and note revision contents in bytes
* @type {int|null}
* @private
*/
this.noteSize = null;
/**
* number of note revisions for this note
* @type {int|null}
* @private
*/
this.revisionCount = null;
}
@@ -175,28 +159,12 @@ class Note extends AbstractEntity {
|| protectedSessionService.isProtectedSessionAvailable()
}
getTitleOrProtected() {
return this.isContentAvailable() ? this.title : '[protected]';
}
/** @returns {Branch[]} */
getParentBranches() {
return this.parentBranches;
}
/**
* Returns &lt;i>strong&lt;/i> (as opposed to &lt;i>weak&lt;/i>) parent branches. See isWeak for details.
*
* @returns {Branch[]}
*/
getStrongParentBranches() {
return this.getParentBranches().filter(branch => !branch.isWeak);
}
/**
* @returns {Branch[]}
* @deprecated use getParentBranches() instead
*/
/** @returns {Branch[]} */
getBranches() {
return this.parentBranches;
}
@@ -239,7 +207,7 @@ class Note extends AbstractEntity {
return undefined;
}
else {
throw new Error(`Cannot find note content for noteId=${this.noteId}`);
throw new Error("Cannot find note content for noteId=" + this.noteId);
}
}
@@ -275,22 +243,6 @@ class Note extends AbstractEntity {
WHERE noteId = ?`, [this.noteId]);
}
get dateCreatedObj() {
return this.dateCreated === null ? null : dayjs(this.dateCreated);
}
get utcDateCreatedObj() {
return this.utcDateCreated === null ? null : dayjs.utc(this.utcDateCreated);
}
get dateModifiedObj() {
return this.dateModified === null ? null : dayjs(this.dateModified);
}
get utcDateModifiedObj() {
return this.utcDateModified === null ? null : dayjs.utc(this.utcDateModified);
}
/** @returns {*} */
getJsonContent() {
const content = this.getContent();
@@ -304,7 +256,7 @@ class Note extends AbstractEntity {
setContent(content, ignoreMissingProtectedSession = false) {
if (content === null || content === undefined) {
throw new Error(`Cannot set null content to note '${this.noteId}'`);
throw new Error(`Cannot set null content to note ${this.noteId}`);
}
if (this.isStringNote()) {
@@ -326,13 +278,13 @@ class Note extends AbstractEntity {
pojo.content = protectedSessionService.encrypt(pojo.content);
}
else if (!ignoreMissingProtectedSession) {
throw new Error(`Cannot update content of noteId '${this.noteId}' since we're out of protected session.`);
throw new Error(`Cannot update content of noteId=${this.noteId} since we're out of protected session.`);
}
}
sql.upsert("note_contents", "noteId", pojo);
const hash = utils.hash(`${this.noteId}|${pojo.content.toString()}`);
const hash = utils.hash(this.noteId + "|" + pojo.content.toString());
entityChangesService.addEntityChange({
entityName: 'note_contents',
@@ -360,7 +312,7 @@ class Note extends AbstractEntity {
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript() {
return (this.type === "code" || this.type === "file" || this.type === 'launcher')
return (this.type === "code" || this.type === "file")
&amp;&amp; (this.mime.startsWith("application/javascript")
|| this.mime === "application/x-javascript"
|| this.mime === "text/javascript");
@@ -400,8 +352,6 @@ class Note extends AbstractEntity {
* @returns {Attribute[]} all note's attributes, including inherited ones
*/
getAttributes(type, name) {
this.__validateTypeName(type, name);
this.__getAttributes([]);
if (type &amp;&amp; name) {
@@ -414,12 +364,10 @@ class Note extends AbstractEntity {
return this.__attributeCache.filter(attr => attr.name === name);
}
else {
// a bit unsafe to return the original array, but defensive copy would be costly
return this.__attributeCache;
return this.__attributeCache.slice();
}
}
/** @private */
__getAttributes(path) {
if (path.includes(this.noteId)) {
return [];
@@ -442,11 +390,7 @@ class Note extends AbstractEntity {
const templateNote = this.becca.notes[ownedAttr.value];
if (templateNote) {
templateAttributes.push(
...templateNote.__getAttributes(newPath)
// template attr is used as a marker for templates, but it's not meant to be inherited
.filter(attr => !(attr.type === 'label' &amp;&amp; (attr.name === 'template' || attr.name === 'workspacetemplate')))
);
templateAttributes.push(...templateNote.__getAttributes(newPath));
}
}
}
@@ -475,10 +419,7 @@ class Note extends AbstractEntity {
return this.__attributeCache;
}
/**
* @private
* @returns {Attribute[]}
*/
/** @returns {Attribute[]} */
__getInheritableAttributes(path) {
if (path.includes(this.noteId)) {
return [];
@@ -491,31 +432,8 @@ class Note extends AbstractEntity {
return this.inheritableAttributeCache;
}
__validateTypeName(type, name) {
if (type &amp;&amp; type !== 'label' &amp;&amp; type !== 'relation') {
throw new Error(`Unrecognized attribute type '${type}'. Only 'label' and 'relation' are possible values.`);
}
if (name) {
const firstLetter = name.charAt(0);
if (firstLetter === '#' || firstLetter === '~') {
throw new Error(`Detect '#' or '~' in the attribute's name. In the API, attribute names should be set without these characters.`);
}
}
}
/**
* @param type
* @param name
* @param [value]
* @returns {boolean}
*/
hasAttribute(type, name, value = null) {
return !!this.getAttributes().find(attr =>
attr.type === type
&amp;&amp; attr.name === name
&amp;&amp; (value === undefined || value === null || attr.value === value)
);
hasAttribute(type, name) {
return !!this.getAttributes().find(attr => attr.type === type &amp;&amp; attr.name === name);
}
getAttributeCaseInsensitive(type, name, value) {
@@ -536,31 +454,27 @@ class Note extends AbstractEntity {
/**
* @param {string} name - label name
* @param {string} [value] - label value
* @returns {boolean} true if label exists (including inherited)
*/
hasLabel(name, value) { return this.hasAttribute(LABEL, name, value); }
hasLabel(name) { return this.hasAttribute(LABEL, name); }
/**
* @param {string} name - label name
* @param {string} [value] - label value
* @returns {boolean} true if label exists (excluding inherited)
*/
hasOwnedLabel(name, value) { return this.hasOwnedAttribute(LABEL, name, value); }
hasOwnedLabel(name) { return this.hasOwnedAttribute(LABEL, name); }
/**
* @param {string} name - relation name
* @param {string} [value] - relation value
* @returns {boolean} true if relation exists (including inherited)
*/
hasRelation(name, value) { return this.hasAttribute(RELATION, name, value); }
hasRelation(name) { return this.hasAttribute(RELATION, name); }
/**
* @param {string} name - relation name
* @param {string} [value] - relation value
* @returns {boolean} true if relation exists (excluding inherited)
*/
hasOwnedRelation(name, value) { return this.hasOwnedAttribute(RELATION, name, value); }
hasOwnedRelation(name) { return this.hasOwnedAttribute(RELATION, name); }
/**
* @param {string} name - label name
@@ -613,11 +527,10 @@ class Note extends AbstractEntity {
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @param {string} [value] - attribute value
* @returns {boolean} true if note has an attribute with given type and name (excluding inherited)
*/
hasOwnedAttribute(type, name, value) {
return !!this.getOwnedAttribute(type, name, value);
hasOwnedAttribute(type, name) {
return !!this.getOwnedAttribute(type, name);
}
/**
@@ -702,18 +615,17 @@ class Note extends AbstractEntity {
}
/**
* @param {string|null} [type] - (optional) attribute type to filter
* @param {string|null} [name] - (optional) attribute name to filter
* @param {string|null} [value] - (optional) attribute value to filter
* @param {string} [type] - (optional) attribute type to filter
* @param {string} [name] - (optional) attribute name to filter
* @returns {Attribute[]} note's "owned" attributes - excluding inherited ones
*/
getOwnedAttributes(type = null, name = null, value = null) {
this.__validateTypeName(type, name);
if (type &amp;&amp; name &amp;&amp; value !== undefined &amp;&amp; value !== null) {
return this.ownedAttributes.filter(attr => attr.type === type &amp;&amp; attr.name === name &amp;&amp; attr.value === value);
getOwnedAttributes(type, name) {
// it's a common mistake to include # or ~ into attribute name
if (name &amp;&amp; ["#", "~"].includes(name[0])) {
name = name.substr(1);
}
else if (type &amp;&amp; name) {
if (type &amp;&amp; name) {
return this.ownedAttributes.filter(attr => attr.type === type &amp;&amp; attr.name === name);
}
else if (type) {
@@ -732,8 +644,8 @@ class Note extends AbstractEntity {
*
* This method can be significantly faster than the getAttribute()
*/
getOwnedAttribute(type, name, value = null) {
const attrs = this.getOwnedAttributes(type, name, value);
getOwnedAttribute(type, name) {
const attrs = this.getOwnedAttributes(type, name);
return attrs.length > 0 ? attrs[0] : null;
}
@@ -750,12 +662,10 @@ class Note extends AbstractEntity {
// this is done so that non-search &amp; non-archived paths are always explored as first when looking for note path
sortParents() {
this.parentBranches.sort((a, b) =>
a.branchId.startsWith('virt-') // FIXME: search virtual notes appear only in froca so this is probably not necessary
|| a.parentNote?.hasInheritableOwnedArchivedLabel() ? 1 : -1);
a.branchId.startsWith('virt-')
|| a.parentNote.hasInheritableOwnedArchivedLabel() ? 1 : -1);
this.parents = this.parentBranches
.map(branch => branch.parentNote)
.filter(note => !!note);
this.parents = this.parentBranches.map(branch => branch.parentNote);
}
/**
@@ -767,22 +677,22 @@ class Note extends AbstractEntity {
*/
getFlatText() {
if (!this.flatTextCache) {
this.flatTextCache = `${this.noteId} ${this.type} ${this.mime} `;
this.flatTextCache = this.noteId + ' ' + this.type + ' ' + this.mime + ' ';
for (const branch of this.parentBranches) {
if (branch.prefix) {
this.flatTextCache += `${branch.prefix} `;
this.flatTextCache += branch.prefix + ' ';
}
}
this.flatTextCache += `${this.title} `;
this.flatTextCache += this.title + ' ';
for (const attr of this.getAttributes()) {
// it's best to use space as separator since spaces are filtered from the search string by the tokenization into words
this.flatTextCache += `${attr.type === 'label' ? '#' : '~'}${attr.name}`;
this.flatTextCache += (attr.type === 'label' ? '#' : '~') + attr.name;
if (attr.value) {
this.flatTextCache += `=${attr.value}`;
this.flatTextCache += '=' + attr.value;
}
this.flatTextCache += ' ';
@@ -891,93 +801,30 @@ class Note extends AbstractEntity {
return Array.from(set);
}
/** @return {Note[]} */
getSearchResultNotes() {
if (this.type !== 'search') {
return [];
}
try {
const searchService = require("../../services/search/services/search");
const {searchResultNoteIds} = searchService.searchFromNote(this);
const becca = this.becca;
return searchResultNoteIds
.map(resultNoteId => becca.notes[resultNoteId])
.filter(note => !!note);
}
catch (e) {
log.error(`Could not resolve search note ${this.noteId}: ${e.message}`);
return [];
}
}
/**
* @returns {{notes: Note[], relationships: Array.&lt;{parentNoteId: string, childNoteId: string}>}}
*/
getSubtree({includeArchived = true, includeHidden = false, resolveSearch = false} = {}) {
/** @returns {Note[]} */
getSubtreeNotes(includeArchived = true) {
const noteSet = new Set();
const relationships = []; // list of tuples parentNoteId -> childNoteId
function resolveSearchNote(searchNote) {
try {
for (const resultNote of searchNote.getSearchResultNotes()) {
addSubtreeNotesInner(resultNote, searchNote);
}
}
catch (e) {
log.error(`Could not resolve search note ${searchNote?.noteId}: ${e.message}`);
}
}
function addSubtreeNotesInner(note, parentNote = null) {
if (note.noteId === '_hidden' &amp;&amp; !includeHidden) {
return;
}
if (parentNote) {
// this needs to happen first before noteSet check to include all clone relationships
relationships.push({
parentNoteId: parentNote.noteId,
childNoteId: note.noteId
});
}
if (noteSet.has(note)) {
return;
}
function addSubtreeNotesInner(note) {
if (!includeArchived &amp;&amp; note.isArchived) {
return;
}
noteSet.add(note);
if (note.type === 'search') {
if (resolveSearch) {
resolveSearchNote(note);
}
}
else {
for (const childNote of note.children) {
addSubtreeNotesInner(childNote, note);
}
for (const childNote of note.children) {
addSubtreeNotesInner(childNote);
}
}
addSubtreeNotesInner(this);
return {
notes: Array.from(noteSet),
relationships
};
return Array.from(noteSet);
}
/** @returns {String[]} */
getSubtreeNoteIds({includeArchived = true, resolveSearch = false} = {}) {
return this.getSubtree({includeArchived, resolveSearch})
.notes
.map(note => note.noteId);
getSubtreeNoteIds(includeArchived = true) {
return this.getSubtreeNotes(includeArchived).map(note => note.noteId);
}
getDescendantNoteIds() {
@@ -1039,13 +886,11 @@ class Note extends AbstractEntity {
this.ancestorCache = [];
for (const parent of this.parents) {
if (noteIds.has(parent.noteId)) {
continue;
if (!noteIds.has(parent.noteId)) {
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
}
this.ancestorCache.push(parent);
noteIds.add(parent.noteId);
for (const ancestorNote of parent.getAncestors()) {
if (!noteIds.has(ancestorNote.noteId)) {
this.ancestorCache.push(ancestorNote);
@@ -1069,10 +914,6 @@ class Note extends AbstractEntity {
return false;
}
isInHiddenSubtree() {
return this.noteId === '_hidden' || this.hasAncestor('_hidden');
}
getTargetRelations() {
return this.targetRelations;
}
@@ -1155,7 +996,7 @@ class Note extends AbstractEntity {
const attributes = this.getOwnedAttributes();
const attr = attributes.find(attr => attr.type === type &amp;&amp; attr.name === name);
value = value?.toString() || "";
value = value !== null &amp;&amp; value !== undefined ? value.toString() : "";
if (attr) {
if (attr.value !== value) {
@@ -1164,7 +1005,7 @@ class Note extends AbstractEntity {
}
}
else {
const Attribute = require("./attribute");
const Attribute = require("./attribute.js");
new Attribute({
noteId: this.noteId,
@@ -1193,17 +1034,10 @@ class Note extends AbstractEntity {
}
/**
* Adds a new attribute to this note. The attribute is saved and returned.
* See addLabel, addRelation for more specific methods.
*
* @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.
*
* @return {Attribute}
*/
addAttribute(type, name, value = "", isInheritable = false, position = 1000) {
const Attribute = require("./attribute");
const Attribute = require("./attribute.js");
return new Attribute({
noteId: this.noteId,
@@ -1215,27 +1049,10 @@ class Note extends AbstractEntity {
}).save();
}
/**
* Adds a new label to this note. The label attribute is saved and returned.
*
* @param {string} name - name of the label, not including the leading #
* @param {string} [value] - text value of the label; optional
*
* @return {Attribute}
*/
addLabel(name, value = "", isInheritable = false) {
return this.addAttribute(LABEL, name, value, isInheritable);
}
/**
* Adds a new relation to this note. The relation attribute is saved and
* returned.
*
* @param {string} name - name of the relation, not including the leading ~
* @param {string} value - ID of the target note of the relation
*
* @return {Attribute}
*/
addRelation(name, targetNoteId, isInheritable = false) {
return this.addAttribute(RELATION, name, targetNoteId, isInheritable);
}
@@ -1317,52 +1134,18 @@ class Note extends AbstractEntity {
return this.searchNotesInSubtree(searchString)[0];
}
/**
* @param parentNoteId
* @returns {{success: boolean, message: string}}
*/
cloneTo(parentNoteId) {
const cloningService = require("../../services/cloning");
const branch = this.becca.getNote(parentNoteId).getParentBranches()[0];
return cloningService.cloneNoteToBranch(this.noteId, branch.branchId);
}
/**
* (Soft) delete a note and all its descendants.
*
* @param {string} [deleteId] - optional delete identified
* @param {TaskContext} [taskContext]
*/
deleteNote(deleteId, taskContext) {
if (this.isDeleted) {
return;
}
if (!deleteId) {
deleteId = utils.randomString(10);
}
if (!taskContext) {
taskContext = new TaskContext('no-progress-reporting');
}
// needs to be run before branches and attributes are deleted and thus attached relations disappear
const handlers = require("../../services/handlers");
handlers.runAttachedRelations(this, 'runOnNoteDeletion', this);
taskContext.noteDeletionHandlerTriggered = true;
for (const branch of this.getParentBranches()) {
branch.deleteBranch(deleteId, taskContext);
}
return cloningService.cloneNoteToParent(this.noteId, branch.branchId);
}
decrypt() {
if (this.isProtected &amp;&amp; !this.isDecrypted &amp;&amp; protectedSessionService.isProtectedSessionAvailable()) {
try {
this.title = protectedSessionService.decryptString(this.title);
this.flatTextCache = null;
this.isDecrypted = true;
}
@@ -1372,51 +1155,8 @@ class Note extends AbstractEntity {
}
}
isLaunchBarConfig() {
return this.type === 'launcher' || ['_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(this.noteId);
}
isOptions() {
return this.noteId.startsWith("options");
}
get isDeleted() {
return !(this.noteId in this.becca.notes) || this.isBeingDeleted;
}
/**
* @return {NoteRevision|null}
*/
saveNoteRevision() {
const content = this.getContent();
if (!content || (Buffer.isBuffer(content) &amp;&amp; content.byteLength === 0)) {
return null;
}
const contentMetadata = this.getContentMetadata();
const noteRevision = new NoteRevision({
noteId: this.noteId,
// title and text should be decrypted now
title: this.title,
type: this.type,
mime: this.mime,
isProtected: this.isProtected,
utcDateLastEdited: this.utcDateModified > contentMetadata.utcDateModified
? this.utcDateModified
: contentMetadata.utcDateModified,
utcDateCreated: dateUtils.utcNowDateTime(),
utcDateModified: dateUtils.utcNowDateTime(),
dateLastEdited: this.dateModified > contentMetadata.dateModified
? this.dateModified
: contentMetadata.dateModified,
dateCreated: dateUtils.localNowDateTime()
}, true).save();
noteRevision.setContent(content);
return noteRevision;
return !(this.noteId in this.becca.notes);
}
beforeSaving() {
@@ -1471,13 +1211,13 @@ module.exports = Note;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -32,22 +32,20 @@ const protectedSessionService = require('../../services/protected_session');
const utils = require('../../services/utils');
const sql = require('../../services/sql');
const dateUtils = require('../../services/date_utils');
const becca = require('../becca');
const becca = require('../becca.js');
const entityChangesService = require('../../services/entity_changes');
const AbstractEntity = require("./abstract_entity");
const AbstractEntity = require("./abstract_entity.js");
/**
* NoteRevision represents snapshot of note's title and content at some point in the past.
* It's used for seamless note versioning.
*
* @extends AbstractEntity
*/
class NoteRevision extends AbstractEntity {
static get entityName() { return "note_revisions"; }
static get primaryKeyName() { return "noteRevisionId"; }
static get hashedProperties() { return ["noteRevisionId", "noteId", "title", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified"]; }
constructor(row, titleDecrypted = false) {
constructor(row) {
super();
/** @type {string} */
@@ -75,10 +73,13 @@ class NoteRevision extends AbstractEntity {
/** @type {number} */
this.contentLength = row.contentLength;
if (this.isProtected &amp;&amp; !titleDecrypted) {
this.title = protectedSessionService.isProtectedSessionAvailable()
? protectedSessionService.decryptString(this.title)
: "[protected]";
if (this.isProtected) {
if (protectedSessionService.isProtectedSessionAvailable()) {
this.title = protectedSessionService.decryptString(this.title);
}
else {
this.title = "[protected]";
}
}
}
@@ -93,8 +94,8 @@ class NoteRevision extends AbstractEntity {
/*
* Note revision content has quite special handling - it's not a separate entity, but a lazily loaded
* part of NoteRevision entity with its own sync. Reason behind this hybrid design is that
* content can be quite large, and it's not necessary to load it / fill memory for any note access even
* part of NoteRevision entity with it's own sync. Reason behind this hybrid design is that
* content can be quite large and it's not necessary to load it / fill memory for any note access even
* if we don't need a content, especially for bulk operations like search.
*
* This is the same approach as is used for Note's content.
@@ -109,7 +110,7 @@ class NoteRevision extends AbstractEntity {
return undefined;
}
else {
throw new Error(`Cannot find note revision content for noteRevisionId=${this.noteRevisionId}`);
throw new Error("Cannot find note revision content for noteRevisionId=" + this.noteRevisionId);
}
}
@@ -152,7 +153,7 @@ class NoteRevision extends AbstractEntity {
sql.upsert("note_revision_contents", "noteRevisionId", pojo);
const hash = utils.hash(`${this.noteRevisionId}|${pojo.content.toString()}`);
const hash = utils.hash(this.noteRevisionId + "|" + pojo.content.toString());
entityChangesService.addEntityChange({
entityName: 'note_revision_contents',
@@ -229,13 +230,13 @@ module.exports = NoteRevision;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -28,13 +28,11 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* Option represents name-value pair, either directly configurable by the user or some system property.
*
* @extends AbstractEntity
*/
class Option extends AbstractEntity {
static get entityName() { return "options"; }
@@ -67,7 +65,9 @@ class Option extends AbstractEntity {
name: this.name,
value: this.value,
isSynced: this.isSynced,
utcDateModified: this.utcDateModified
utcDateModified: this.utcDateModified,
// utcDateCreated is scheduled for removal so the value does not matter
utcDateCreated: dateUtils.utcNowDateTime()
}
}
}
@@ -83,13 +83,13 @@ module.exports = Option;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -28,13 +28,11 @@
<article>
<pre class="prettyprint source linenums"><code>"use strict";
const dateUtils = require('../../services/date_utils');
const AbstractEntity = require("./abstract_entity");
const dateUtils = require('../../services/date_utils.js');
const AbstractEntity = require("./abstract_entity.js");
/**
* RecentNote represents recently visited note.
*
* @extends AbstractEntity
*/
class RecentNote extends AbstractEntity {
static get entityName() { return "recent_notes"; }
@@ -71,13 +69,13 @@ module.exports = RecentNote;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -237,7 +237,7 @@
<td class="description last">text, code, file, image, search, book, relationMap, canvas - MANDATORY</td>
<td class="description last">text, code, file, image, search, book, relation-map - MANDATORY</td>
</tr>
@@ -391,7 +391,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#line212">line 212</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line208">line 208</a>
</li></ul></dd>
@@ -579,7 +579,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#line173">line 173</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line169">line 169</a>
</li></ul></dd>
@@ -767,7 +767,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#line233">line 233</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line229">line 229</a>
</li></ul></dd>
@@ -1053,635 +1053,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#line240">line 240</a>
</li></ul></dd>
</dl>
<h4 class="name" id="CreateOrUpdateLauncher">CreateOrUpdateLauncher</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>id</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
</td>
<td class="default">
</td>
<td class="description last">id of the launcher, only alphanumeric at least 6 characters long</td>
</tr>
<tr>
<td class="name"><code>type</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
</td>
<td class="default">
</td>
<td class="description last">one of
* "note" - activating the launcher will navigate to the target note (specified in targetNoteId param)
* "script" - activating the launcher will execute the script (specified in scriptNoteId param)
* "customWidget" - the launcher will be rendered with a custom widget (specified in widgetNoteId param)</td>
</tr>
<tr>
<td class="name"><code>title</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
</td>
<td class="default">
</td>
<td class="description last"></td>
</tr>
<tr>
<td class="name"><code>isVisible</code></td>
<td class="type">
<span class="param-type">boolean</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
false
</td>
<td class="description last">if true, will be created in the "Visible launchers", otherwise in "Available launchers"</td>
</tr>
<tr>
<td class="name"><code>icon</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
</td>
<td class="description last">name of the boxicon to be used (e.g. "bx-time")</td>
</tr>
<tr>
<td class="name"><code>keyboardShortcut</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
</td>
<td class="description last">will activate the target note/script upon pressing, e.g. "ctrl+e"</td>
</tr>
<tr>
<td class="name"><code>targetNoteId</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
</td>
<td class="description last">for type "note"</td>
</tr>
<tr>
<td class="name"><code>scriptNoteId</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
</td>
<td class="description last">for type "script"</td>
</tr>
<tr>
<td class="name"><code>widgetNoteId</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="default">
</td>
<td class="description last">for type "customWidget"</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#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">
&lt;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">
&lt;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">
&lt;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>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line236">line 236</a>
</li></ul></dd>
@@ -1711,13 +1083,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -50,13 +50,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -28,6 +28,8 @@
<header>
</header>
<article>
@@ -36,50 +38,6 @@
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line3">line 3</a>
</li></ul></dd>
</dl>
</div>
@@ -250,7 +208,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line361">line 361</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line352">line 352</a>
</li></ul></dd>
@@ -430,7 +388,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line352">line 352</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line343">line 343</a>
</li></ul></dd>
@@ -632,7 +590,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line342">line 342</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line333">line 333</a>
</li></ul></dd>
@@ -834,7 +792,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line318">line 318</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line309">line 309</a>
</li></ul></dd>
@@ -1036,7 +994,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line329">line 329</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line320">line 320</a>
</li></ul></dd>
@@ -1238,7 +1196,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line308">line 308</a>
<a href="services_sql.js.html">services/sql.js</a>, <a href="services_sql.js.html#line299">line 299</a>
</li></ul></dd>
@@ -1294,13 +1252,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -42,10 +42,6 @@ const appInfo = require('./app_info');
const searchService = require('./search/services/search');
const SearchContext = require("./search/search_context");
const becca = require("../becca/becca");
const ws = require("./ws");
const SpacedUpdate = require("./spaced_update");
const specialNotesService = require("./special_notes");
const branchService = require("./branches.js");
/**
* This is the main backend API interface for scripts. It's published in the local "api" object.
@@ -166,18 +162,18 @@ function BackendScriptApi(currentNote, apiParams) {
this.getNoteWithLabel = attributeService.getNoteWithLabel;
/**
* If there's no branch between note and parent note, create one. Otherwise, do nothing.
* If there's no branch between note and parent note, create one. Otherwise do nothing.
*
* @method
* @param {string} noteId
* @param {string} parentNoteId
* @param {string} prefix - if branch will be created between note and parent note, set this prefix
* @param {string} prefix - if branch will be create between note and parent note, set this prefix
* @returns {void}
*/
this.ensureNoteIsPresentInParent = cloningService.ensureNoteIsPresentInParent;
/**
* If there's a branch between note and parent note, remove it. Otherwise, do nothing.
* If there's a branch between note and parent note, remove it. Otherwise do nothing.
*
* @method
* @param {string} noteId
@@ -193,7 +189,7 @@ function BackendScriptApi(currentNote, apiParams) {
* @param {boolean} present - true if we want the branch to exist, false if we want it gone
* @param {string} noteId
* @param {string} parentNoteId
* @param {string} prefix - if branch will be created between note and parent note, set this prefix
* @param {string} prefix - if branch will be create between note and parent note, set this prefix
* @returns {void}
*/
this.toggleNoteInParent = cloningService.toggleNoteInParent;
@@ -242,7 +238,7 @@ function BackendScriptApi(currentNote, apiParams) {
* @property {string} parentNoteId - MANDATORY
* @property {string} title - MANDATORY
* @property {string|buffer} content - MANDATORY
* @property {string} type - text, code, file, image, search, book, relationMap, canvas - MANDATORY
* @property {string} type - text, code, file, image, search, book, relation-map - MANDATORY
* @property {string} mime - value is derived from default mimes for type
* @property {boolean} isProtected - default is false
* @property {boolean} isExpanded - default is false
@@ -320,34 +316,12 @@ function BackendScriptApi(currentNote, apiParams) {
});
};
this.logMessages = {};
this.logSpacedUpdates = {};
/**
* Log given message to trilium logs and log pane in UI
* Log given message to trilium logs.
*
* @param message
*/
this.log = message => {
log.info(message);
const {noteId} = this.startNote;
this.logMessages[noteId] = this.logMessages[noteId] || [];
this.logSpacedUpdates[noteId] = this.logSpacedUpdates[noteId] || new SpacedUpdate(() => {
const messages = this.logMessages[noteId];
this.logMessages[noteId] = [];
ws.sendMessageToAllClients({
type: 'api-log-messages',
noteId,
messages
});
}, 100);
this.logMessages[noteId].push(message);
this.logSpacedUpdates[noteId].scheduleUpdate();
};
this.log = message => log.info(`Script "${currentNote.title}" (${currentNote.noteId}): ${message}`);
/**
* Returns root note of the calendar.
@@ -362,27 +336,14 @@ function BackendScriptApi(currentNote, apiParams) {
*
* @method
* @param {string} date in YYYY-MM-DD format
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @returns {Note|null}
* @deprecated use getDayNote instead
*/
this.getDateNote = dateNoteService.getDayNote;
/**
* Returns day note for given date. If such note doesn't exist, it is created.
*
* @method
* @param {string} date in YYYY-MM-DD format
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @returns {Note|null}
*/
this.getDayNote = dateNoteService.getDayNote;
this.getDateNote = dateNoteService.getDateNote;
/**
* Returns today's day note. If such note doesn't exist, it is created.
*
* @method
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @returns {Note|null}
*/
this.getTodayNote = dateNoteService.getTodayNote;
@@ -392,8 +353,7 @@ function BackendScriptApi(currentNote, apiParams) {
*
* @method
* @param {string} date in YYYY-MM-DD format
* @param {object} [options] - "startOfTheWeek" - either "monday" (default) or "sunday"
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @param {object} options - "startOfTheWeek" - either "monday" (default) or "sunday"
* @returns {Note|null}
*/
this.getWeekNote = dateNoteService.getWeekNote;
@@ -403,7 +363,6 @@ function BackendScriptApi(currentNote, apiParams) {
*
* @method
* @param {string} date in YYYY-MM format
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @returns {Note|null}
*/
this.getMonthNote = dateNoteService.getMonthNote;
@@ -413,40 +372,16 @@ function BackendScriptApi(currentNote, apiParams) {
*
* @method
* @param {string} year in YYYY format
* @param {Note} [rootNote] - specify calendar root note, normally leave empty to use default calendar
* @returns {Note|null}
*/
this.getYearNote = dateNoteService.getYearNote;
/**
* @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).
@@ -503,101 +438,12 @@ function BackendScriptApi(currentNote, apiParams) {
* @method
* @deprecated - this is now no-op since all the changes should be gracefully handled per widget
*/
this.refreshTree = () => {
console.warn("api.refreshTree() is a NO-OP and can be removed from your script.")
};
this.refreshTree = () => {};
/**
* @return {{syncVersion, appVersion, buildRevision, dbVersion, dataDirectory, buildDate}|*} - object representing basic info about running Trilium version
*/
this.getAppInfo = () => appInfo
/**
* @typedef {Object} CreateOrUpdateLauncher
* @property {string} id - id of the launcher, only alphanumeric at least 6 characters long
* @property {string} type - one of
* * "note" - activating the launcher will navigate to the target note (specified in targetNoteId param)
* * "script" - activating the launcher will execute the script (specified in scriptNoteId param)
* * "customWidget" - the launcher will be rendered with a custom widget (specified in widgetNoteId param)
* @property {string} title
* @property {boolean} [isVisible=false] - if true, will be created in the "Visible launchers", otherwise in "Available launchers"
* @property {string} [icon] - name of the boxicon to be used (e.g. "bx-time")
* @property {string} [keyboardShortcut] - will activate the target note/script upon pressing, e.g. "ctrl+e"
* @property {string} [targetNoteId] - for type "note"
* @property {string} [scriptNoteId] - for type "script"
* @property {string} [widgetNoteId] - for type "customWidget"
*/
/**
* Creates a new launcher to the launchbar. If the launcher (id) already exists, it will be updated.
*
* @param {CreateOrUpdateLauncher} opts
*/
this.createOrUpdateLauncher = opts => {
if (!opts.id) { throw new Error("ID is a mandatory parameter for api.createOrUpdateLauncher(opts)"); }
if (!opts.id.match(/[a-z0-9]{6,1000}/i)) { throw new Error(`ID must be an alphanumeric string at least 6 characters long.`); }
if (!opts.type) { throw new Error("Launcher Type is a mandatory parameter for api.createOrUpdateLauncher(opts)"); }
if (!["note", "script", "customWidget"].includes(opts.type)) { throw new Error(`Given launcher type '${opts.type}'`); }
if (!opts.title?.trim()) { throw new Error("Title is a mandatory parameter for api.createOrUpdateLauncher(opts)"); }
if (opts.type === 'note' &amp;&amp; !opts.targetNoteId) { throw new Error("targetNoteId is mandatory for launchers of type 'note'"); }
if (opts.type === 'script' &amp;&amp; !opts.scriptNoteId) { throw new Error("scriptNoteId is mandatory for launchers of type 'script'"); }
if (opts.type === 'customWidget' &amp;&amp; !opts.widgetNoteId) { throw new Error("widgetNoteId is mandatory for launchers of type 'customWidget'"); }
const parentNoteId = !!opts.isVisible ? '_lbVisibleLaunchers' : '_lbAvailableLaunchers';
const noteId = 'al_' + opts.id;
const launcherNote =
becca.getNote(opts.id) ||
specialNotesService.createLauncher({
noteId: noteId,
parentNoteId: parentNoteId,
launcherType: opts.type,
}).note;
if (launcherNote.title !== opts.title) {
launcherNote.title = opts.title;
launcherNote.save();
}
if (launcherNote.getParentBranches().length === 1) {
const branch = launcherNote.getParentBranches()[0];
if (branch.parentNoteId !== parentNoteId) {
branchService.moveBranchToNote(branch, parentNoteId);
}
}
if (opts.type === 'note') {
launcherNote.setRelation('target', opts.targetNoteId);
} else if (opts.type === 'script') {
launcherNote.setRelation('script', opts.scriptNoteId);
} else if (opts.type === 'customWidget') {
launcherNote.setRelation('widget', opts.widgetNoteId);
} else {
throw new Error(`Unrecognized launcher type '${opts.type}'`);
}
if (opts.keyboardShortcut) {
launcherNote.setLabel('keyboardShortcut', opts.keyboardShortcut);
} else {
launcherNote.removeLabel('keyboardShortcut');
}
if (opts.icon) {
launcherNote.setLabel('iconClass', `bx ${opts.icon}`);
} else {
launcherNote.removeLabel('keyboardShortcut');
}
};
/**
* This object contains "at your risk" and "no BC guarantees" objects for advanced use cases.
*
* @type {{becca: Becca}}
*/
this.__private = {
becca
}
}
module.exports = BackendScriptApi;
@@ -611,13 +457,13 @@ module.exports = BackendScriptApi;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -36,13 +36,10 @@ const log = require('./log');
const Database = require('better-sqlite3');
const dataDir = require('./data_dir');
const cls = require('./cls');
const fs = require("fs-extra");
const dbConnection = new Database(dataDir.DOCUMENT_PATH);
dbConnection.pragma('journal_mode = WAL');
const LOG_ALL_QUERIES = false;
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `SIGTERM`].forEach(eventType => {
process.on(eventType, () => {
if (dbConnection) {
@@ -56,20 +53,14 @@ const LOG_ALL_QUERIES = false;
function insert(tableName, rec, replace = false) {
const keys = Object.keys(rec);
if (keys.length === 0) {
log.error(`Can't insert empty object into table ${tableName}`);
log.error("Can't insert empty object into table " + tableName);
return;
}
const columns = keys.join(", ");
const questionMarks = keys.map(p => "?").join(", ");
const query = `INSERT
${replace ? "OR REPLACE" : ""} INTO
${tableName}
(
${columns}
)
VALUES (${questionMarks})`;
const query = "INSERT " + (replace ? "OR REPLACE" : "") + " INTO " + tableName + "(" + columns + ") VALUES (" + questionMarks + ")";
const res = execute(query, Object.values(rec));
@@ -83,13 +74,13 @@ function replace(tableName, rec) {
function upsert(tableName, primaryKey, rec) {
const keys = Object.keys(rec);
if (keys.length === 0) {
log.error(`Can't upsert empty object into table ${tableName}`);
log.error("Can't upsert empty object into table " + tableName);
return;
}
const columns = keys.join(", ");
const questionMarks = keys.map(colName => `@${colName}`).join(", ");
const questionMarks = keys.map(colName => "@" + colName).join(", ");
const updateMarks = keys.map(colName => `${colName} = @${colName}`).join(", ");
@@ -126,7 +117,13 @@ function getRowOrNull(query, params = []) {
}
function getValue(query, params = []) {
return wrap(query, s => s.pluck().get(params));
const row = getRowOrNull(query, params);
if (!row) {
return null;
}
return row[Object.keys(row)[0]];
}
// smaller values can result in better performance due to better usage of statement cache
@@ -170,37 +167,48 @@ function getRawRows(query, params = []) {
}
function iterateRows(query, params = []) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
return stmt(query).iterate(params);
}
function getMap(query, params = []) {
const map = {};
const results = getRawRows(query, params);
const results = getRows(query, params);
for (const row of results) {
map[row[0]] = row[1];
const keys = Object.keys(row);
map[row[keys[0]]] = row[keys[1]];
}
return map;
}
function getColumn(query, params = []) {
return wrap(query, s => s.pluck().all(params));
const list = [];
const result = getRows(query, params);
if (result.length === 0) {
return list;
}
const key = Object.keys(result[0])[0];
for (const row of result) {
list.push(row[key]);
}
return list;
}
function execute(query, params = []) {
return wrap(query, s => s.run(params));
}
function executeMany(query, params) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
function executeWithoutTransaction(query, params = []) {
dbConnection.run(query, params);
}
function executeMany(query, params) {
while (params.length > 0) {
const curParams = params.slice(0, Math.min(params.length, PARAM_LIMIT));
params = params.slice(curParams.length);
@@ -221,10 +229,6 @@ function executeMany(query, params) {
}
function executeScript(query) {
if (LOG_ALL_QUERIES) {
console.log(query);
}
return dbConnection.exec(query);
}
@@ -232,10 +236,6 @@ function wrap(query, func) {
const startTimestamp = Date.now();
let result;
if (LOG_ALL_QUERIES) {
console.log(query);
}
try {
result = func(stmt(query));
}
@@ -276,9 +276,9 @@ function transactional(func) {
return ret;
}
catch (e) {
const entityChangeIds = cls.getAndClearEntityChangeIds();
const entityChanges = cls.getAndClearEntityChangeIds();
if (entityChangeIds.length > 0) {
if (entityChanges.length > 0) {
log.info("Transaction rollback dirtied the becca, forcing reload.");
require('../becca/becca_loader').load();
@@ -306,20 +306,11 @@ function fillParamList(paramIds, truncate = true) {
}
// doing it manually to avoid this showing up on the sloq query list
const s = stmt(`INSERT INTO param_list VALUES ${paramIds.map(paramId => `(?)`).join(',')}`, paramIds);
const s = stmt(`INSERT INTO param_list VALUES ` + paramIds.map(paramId => `(?)`).join(','), paramIds);
s.run(paramIds);
}
async function copyDatabase(targetFilePath) {
try {
fs.unlinkSync(targetFilePath);
} catch (e) {
} // unlink throws exception if the file did not exist
await dbConnection.backup(targetFilePath);
}
module.exports = {
dbConnection,
insert,
@@ -387,12 +378,12 @@ module.exports = {
* @param {object[]} [params] - array of params if needed
*/
execute,
executeWithoutTransaction,
executeMany,
executeScript,
transactional,
upsert,
fillParamList,
copyDatabase
fillParamList
};
</code></pre>
</article>
@@ -404,13 +395,13 @@ module.exports = {
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="AbstractEntity.html">AbstractEntity</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -727,108 +727,6 @@ and relation (representing named relationship between source and target note)</d
<h4 class="name" id="getTargetNote"><span class="type-signature">(async) </span>getTargetNote<span class="signature">()</span><span class="type-signature"> &rarr; {Promise.&lt;<a href="NoteShort.html">NoteShort</a>>}</span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_attribute.js.html">entities/attribute.js</a>, <a href="entities_attribute.js.html#line37">line 37</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">Promise.&lt;<a href="NoteShort.html">NoteShort</a>></span>
</dd>
</dl>
@@ -844,13 +742,13 @@ and relation (representing named relationship between source and target note)</d
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1056,13 +1056,13 @@ parents.</div>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

File diff suppressed because it is too large Load Diff

View File

@@ -775,13 +775,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

File diff suppressed because it is too large Load Diff

View File

@@ -61,19 +61,8 @@ class Attribute {
return this.froca.notes[this.noteId];
}
/** @returns {Promise&lt;NoteShort>} */
async getTargetNote() {
const targetNoteId = this.targetNoteId;
return await this.froca.getNote(targetNoteId, true);
}
get targetNoteId() { // alias
if (this.type !== 'relation') {
throw new Error(`Attribute ${this.attributeId} is not a relation`);
}
return this.value;
return this.type === 'relation' ? this.value : undefined;
}
get isAutoLink() {
@@ -115,13 +104,13 @@ export default Attribute;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -80,12 +80,6 @@ class Branch {
get toString() {
return `Branch(branchId=${this.branchId})`;
}
get pojo() {
const pojo = {...this};
delete pojo.froca;
return pojo;
}
}
export default Branch;
@@ -99,13 +93,13 @@ export default Branch;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -76,13 +76,13 @@ export default NoteComplement;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -31,8 +31,6 @@ import noteAttributeCache from "../services/note_attribute_cache.js";
import ws from "../services/ws.js";
import options from "../services/options.js";
import froca from "../services/froca.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import cssClassManager from "../services/css_class_manager.js";
const LABEL = 'label';
const RELATION = 'relation';
@@ -43,15 +41,10 @@ const NOTE_TYPE_ICONS = {
"code": "bx bx-code",
"render": "bx bx-extension",
"search": "bx bx-file-find",
"relationMap": "bx bx-map-alt",
"relation-map": "bx bx-map-alt",
"book": "bx bx-book",
"noteMap": "bx bx-map-alt",
"mermaid": "bx bx-selection",
"canvas": "bx bx-pen",
"webView": "bx bx-globe-alt",
"launcher": "bx bx-link",
"doc": "bx bxs-file-doc",
"contentWidget": "bx bxs-widget"
"note-map": "bx bx-map-alt",
"mermaid": "bx bx-selection"
};
/**
@@ -147,7 +140,7 @@ class NoteShort {
async getContent() {
// we're not caching content since these objects are in froca and as such pretty long lived
const note = await server.get(`notes/${this.noteId}`);
const note = await server.get("notes/" + this.noteId);
return note.content;
}
@@ -159,44 +152,24 @@ class NoteShort {
return JSON.parse(content);
}
catch (e) {
console.log(`Cannot parse content of note '${this.noteId}': `, e.message);
console.log(`Cannot parse content of note ${this.noteId}: `, e.message);
return null;
}
}
/**
* @returns {string[]}
*/
getParentBranchIds() {
/** @returns {string[]} */
getBranchIds() {
return Object.values(this.parentToBranch);
}
/**
* @returns {string[]}
* @deprecated use getParentBranchIds() instead
*/
getBranchIds() {
return this.getParentBranchIds();
}
/**
* @returns {Branch[]}
*/
getParentBranches() {
/** @returns {Branch[]} */
getBranches() {
const branchIds = Object.values(this.parentToBranch);
return this.froca.getBranches(branchIds);
}
/**
* @returns {Branch[]}
* @deprecated use getParentBranches() instead
*/
getBranches() {
return this.getParentBranches();
}
/** @returns {boolean} */
hasChildren() {
return this.children.length > 0;
@@ -296,11 +269,7 @@ class NoteShort {
const templateNote = this.froca.notes[templateAttr.value];
if (templateNote &amp;&amp; templateNote.noteId !== this.noteId) {
attrArrs.push(
templateNote.__getCachedAttributes(newPath)
// template attr is used as a marker for templates, but it's not meant to be inherited
.filter(attr => !(attr.type === 'label' &amp;&amp; (attr.name === 'template' || attr.name === 'workspacetemplate')))
);
attrArrs.push(templateNote.__getCachedAttributes(newPath));
}
}
@@ -320,7 +289,7 @@ class NoteShort {
}
isRoot() {
return this.noteId === 'root';
return this.noted
}
getAllNotePaths(encounteredNoteIds = null) {
@@ -372,7 +341,7 @@ class NoteShort {
isInHoistedSubTree: path.includes(hoistedNotePath),
isArchived: path.find(noteId => froca.notes[noteId].hasLabel('archived')),
isSearch: path.find(noteId => froca.notes[noteId].type === 'search'),
isHidden: path.includes('_hidden')
isHidden: path.includes("hidden")
}));
notePaths.sort((a, b) => {
@@ -382,8 +351,6 @@ class NoteShort {
return a.isSearch ? 1 : -1;
} else if (a.isArchived !== b.isArchived) {
return a.isArchived ? 1 : -1;
} else if (a.isHidden !== b.isHidden) {
return a.isHidden ? 1 : -1;
} else {
return a.notePath.length - b.notePath.length;
}
@@ -393,8 +360,6 @@ class NoteShort {
}
__filterAttrs(attributes, type, name) {
this.__validateTypeName(type, name);
if (!type &amp;&amp; !name) {
return attributes;
} else if (type &amp;&amp; name) {
@@ -412,19 +377,6 @@ class NoteShort {
return attrs.filter(attr => attr.isInheritable);
}
__validateTypeName(type, name) {
if (type &amp;&amp; type !== 'label' &amp;&amp; type !== 'relation') {
throw new Error(`Unrecognized attribute type '${type}'. Only 'label' and 'relation' are possible values.`);
}
if (name) {
const firstLetter = name.charAt(0);
if (firstLetter === '#' || firstLetter === '~') {
throw new Error(`Detect '#' or '~' in the attribute's name. In the API, attribute names should be set without these characters.`);
}
}
}
/**
* @param {string} [name] - label name to filter
* @returns {Attribute[]} all note's labels (attributes with type label), including inherited ones
@@ -454,9 +406,6 @@ class NoteShort {
else if (this.noteId === 'root') {
return "bx bx-chevrons-right";
}
if (this.noteId === '_share') {
return "bx bx-share-alt";
}
else if (this.type === 'text') {
if (this.isFolder()) {
return "bx bx-folder";
@@ -473,11 +422,6 @@ class NoteShort {
}
}
getColorClass() {
const color = this.getLabelValue("color");
return cssClassManager.createClassForColor(color);
}
isFolder() {
return this.type === 'search'
|| this.getFilteredChildBranches().length > 0;
@@ -695,22 +639,17 @@ class NoteShort {
return [];
}
const promotedAttrs = this.getAttributes()
return this.getAttributes()
.filter(attr => attr.isDefinition())
.filter(attr => {
const def = attr.getDefinition();
return def &amp;&amp; def.isPromoted;
});
// attrs are not resorted if position changes after initial load
promotedAttrs.sort((a, b) => a.position &lt; b.position ? -1 : 1);
return promotedAttrs;
}
hasAncestor(ancestorNoteId, visitedNoteIds = null) {
if (this.noteId === ancestorNoteId) {
hasAncestor(ancestorNote, visitedNoteIds = null) {
if (this.noteId === ancestorNote.noteId) {
return true;
}
@@ -724,13 +663,13 @@ class NoteShort {
visitedNoteIds.add(this.noteId);
for (const templateNote of this.getTemplateNotes()) {
if (templateNote.hasAncestor(ancestorNoteId, visitedNoteIds)) {
if (templateNote.hasAncestor(ancestorNote, visitedNoteIds)) {
return true;
}
}
for (const parentNote of this.getParentNotes()) {
if (parentNote.hasAncestor(ancestorNoteId, visitedNoteIds)) {
if (parentNote.hasAncestor(ancestorNote, visitedNoteIds)) {
return true;
}
}
@@ -738,10 +677,6 @@ class NoteShort {
return false;
}
isInHiddenSubtree() {
return this.noteId === '_hidden' || this.hasAncestor('_hidden');
}
/**
* @deprecated NOOP
*/
@@ -805,7 +740,7 @@ class NoteShort {
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript() {
return (this.type === "code" || this.type === "file" || this.type === 'launcher')
return (this.type === "code" || this.type === "file")
&amp;&amp; (this.mime.startsWith("application/javascript")
|| this.mime === "application/x-javascript"
|| this.mime === "text/javascript");
@@ -842,47 +777,15 @@ class NoteShort {
if (env === "frontend") {
const bundleService = (await import("../services/bundle.js")).default;
return await bundleService.getAndExecuteBundle(this.noteId);
await bundleService.getAndExecuteBundle(this.noteId);
}
else if (env === "backend") {
const resp = await server.post(`script/run/${this.noteId}`);
await server.post('script/run/' + this.noteId);
}
else {
throw new Error(`Unrecognized env type ${env} for note ${this.noteId}`);
}
}
isShared() {
for (const parentNoteId of this.parents) {
if (parentNoteId === 'root' || parentNoteId === 'none') {
continue;
}
const parentNote = froca.notes[parentNoteId];
if (!parentNote || parentNote.type === 'search') {
continue;
}
if (parentNote.noteId === '_share' || parentNote.isShared()) {
return true;
}
}
return false;
}
isContentAvailable() {
return !this.isProtected || protectedSessionHolder.isProtectedSessionAvailable()
}
isLaunchBarConfig() {
return this.type === 'launcher' || ['_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(this.noteId);
}
isOptions() {
return this.noteId.startsWith("options");
}
}
export default NoteShort;
@@ -896,13 +799,13 @@ export default NoteShort;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -156,7 +156,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line37">line 37</a>
<a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line34">line 34</a>
</li></ul></dd>
@@ -194,7 +194,7 @@
<h4 class="name" id="AddButtonToToolbarOptions">AddButtonToToolbarOptions</h4>
<h4 class="name" id="ToolbarButtonOptions">ToolbarButtonOptions</h4>
@@ -241,38 +241,6 @@
<tbody>
<tr>
<td class="name"><code>id</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="attributes">
&lt;optional><br>
</td>
<td class="description last">id of the button, used to identify the old instances of this button to be replaced
ID is optional because of BC, but not specifying it is deprecated. ID can be alphanumeric only.</td>
</tr>
<tr>
<td class="name"><code>title</code></td>
@@ -427,7 +395,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line108">line 108</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line104">line 104</a>
</li></ul></dd>
@@ -457,13 +425,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -50,13 +50,13 @@
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1,170 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Class: exports</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Class: exports</h1>
<section>
<header>
<h2><span class="attribs"><span class="type-signature"></span></span>exports<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description">TODO: rename, it's not collapsible anymore</div>
</header>
<article>
<div class="container-overview">
<h2>Constructor</h2>
<h4 class="name" id="exports"><span class="type-signature"></span>new exports<span class="signature">()</span><span class="type-signature"></span></h4>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line15">line 15</a>
</li></ul></dd>
</dl>
</div>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -37,11 +37,10 @@ import dateNotesService from './date_notes.js';
import searchService from './search.js';
import CollapsibleWidget from '../widgets/collapsible_widget.js';
import ws from "./ws.js";
import appContext from "../components/app_context.js";
import appContext from "./app_context.js";
import NoteContextAwareWidget from "../widgets/note_context_aware_widget.js";
import NoteContextCachingWidget from "../widgets/note_context_caching_widget.js";
import BasicWidget from "../widgets/basic_widget.js";
import SpacedUpdate from "./spaced_update.js";
import shortcutService from "./shortcuts.js";
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@@ -50,6 +49,8 @@ import shortcutService from "./shortcuts.js";
* @hideconstructor
*/
function FrontendScriptApi(startNote, currentNote, originEntity = null, $container = null) {
const $pluginButtons = $("#plugin-buttons");
/** @property {jQuery} container of all the rendered script content */
this.$container = $container;
@@ -66,9 +67,24 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
/** @property {CollapsibleWidget} */
this.CollapsibleWidget = CollapsibleWidget;
/**
* @property {NoteContextAwareWidget}
* @deprecated use NoteContextAwareWidget instead
*/
this.TabAwareWidget = NoteContextAwareWidget;
/** @property {NoteContextAwareWidget} */
this.NoteContextAwareWidget = NoteContextAwareWidget;
/**
* @property {NoteContextCachingWidget}
* @deprecated use NoteContextCachingWidget instead
*/
this.TabCachingWidget = NoteContextCachingWidget;
/** @property {NoteContextAwareWidget} */
this.NoteContextCachingWidget = NoteContextCachingWidget;
/** @property {BasicWidget} */
this.BasicWidget = BasicWidget;
@@ -114,29 +130,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
};
/**
* Open a note in a new split.
*
* @param {string} notePath (or noteId)
* @param {boolean} activate - set to true to activate the new split, false to stay on the current split
* @return {Promise&lt;void>}
*/
this.openSplitWithNote = async (notePath, activate) => {
await ws.waitForMaxKnownEntityChangeId();
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
const {ntxId} = subContexts[subContexts.length - 1];
appContext.triggerCommand("openNewNoteSplit", {ntxId, notePath});
if (activate) {
appContext.triggerEvent('focusAndSelectTitle');
}
};
/**
* @typedef {Object} AddButtonToToolbarOptions
* @property {string} [id] - id of the button, used to identify the old instances of this button to be replaced
* ID is optional because of BC, but not specifying it is deprecated. ID can be alphanumeric only.
* @typedef {Object} ToolbarButtonOptions
* @property {string} title
* @property {string} [icon] - name of the boxicon to be used (e.g. "time" for "bx-time" icon)
* @property {function} action - callback handling the click on the button
@@ -144,19 +138,48 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
*/
/**
* Adds a new launcher to the launchbar. If the launcher (id) already exists, it will be updated.
* Adds new button the the plugin area.
*
* @deprecated you can now create/modify launchers in the top-left Menu -> Configure Launchbar
* for special needs there's also backend API's createOrUpdateLauncher()
* @param {AddButtonToToolbarOptions} opts
* @param {ToolbarButtonOptions} opts
*/
this.addButtonToToolbar = async opts => {
console.warn("api.addButtonToToolbar() has been deprecated since v0.58 and may be removed in the future. Use Menu -> Configure Launchbar to create/update launchers instead.");
this.addButtonToToolbar = opts => {
const buttonId = "toolbar-button-" + opts.title.replace(/\s/g, "-");
const {action, ...reqBody} = opts;
reqBody.action = action.toString();
let button;
if (utils.isMobile()) {
$('#plugin-buttons-placeholder').remove();
button = $('&lt;a class="dropdown-item" href="#">')
.on('click', () => {
setTimeout(() => $pluginButtons.dropdown('hide'), 0);
});
await server.put('special-notes/api-script-launcher', reqBody);
if (opts.icon) {
button.append($("&lt;span>").addClass("bx bx-" + opts.icon))
.append("&amp;nbsp;");
}
button.append($("&lt;span>").text(opts.title));
} else {
button = $('&lt;span class="button-widget icon-action bx" data-toggle="tooltip" title="" data-placement="right">&lt;/span>')
.addClass("bx bx-" + (opts.icon || "question-mark"));
button.attr("title", opts.title);
button.tooltip({html: true});
}
button = button.on('click', opts.action);
button.attr('id', buttonId);
if ($("#" + buttonId).replaceWith(button).length === 0) {
$pluginButtons.append(button);
}
if (opts.shortcut) {
utils.bindGlobalShortcut(opts.shortcut, opts.action);
button.attr("title", "Shortcut " + opts.shortcut);
}
};
function prepareParams(params) {
@@ -166,7 +189,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
return params.map(p => {
if (typeof p === "function") {
return `!@#Function: ${p.toString()}`;
return "!@#Function: " + p.toString();
}
else {
return p;
@@ -202,7 +225,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
return ret.executionResult;
}
else {
throw new Error(`server error: ${ret.error}`);
throw new Error("server error: " + ret.error);
}
};
@@ -304,24 +327,6 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
*/
this.showError = toastService.showError;
/**
* Trigger command.
*
* @method
* @param {string} name
* @param {object} data
*/
this.triggerCommand = (name, data) => appContext.triggerCommand(name, data);
/**
* Trigger event.
*
* @method
* @param {string} name
* @param {object} data
*/
this.triggerEvent = (name, data) => appContext.triggerEvent(name, data);
/**
* @method
* @deprecated - this is now no-op since all the changes should be gracefully handled per widget
@@ -336,112 +341,37 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
* @param {object} [params]
* @param {boolean} [params.showTooltip=true] - enable/disable tooltip on the link
* @param {boolean} [params.showNotePath=false] - show also whole note's path as part of the link
* @param {boolean} [params.showNoteIcon=false] - show also note icon before the title
* @param {string} [params.title=] - custom link tile with note's title as default
* @param {string} [title=] - custom link tile with note's title as default
*/
this.createNoteLink = linkService.createNoteLink;
/**
* Adds given text to the editor cursor
*
* @deprecated use addTextToActiveContextEditor() instead
* @param {string} text - this must be clear text, HTML is not supported.
* @method
*/
this.addTextToActiveTabEditor = text => {
console.warn("api.addTextToActiveTabEditor() is deprecated, use addTextToActiveContextEditor() instead.");
return appContext.triggerCommand('addTextToActiveEditor', {text});
};
/**
* Adds given text to the editor cursor
*
* @param {string} text - this must be clear text, HTML is not supported.
* @method
*/
this.addTextToActiveContextEditor = text => appContext.triggerCommand('addTextToActiveEditor', {text});
/**
* @method
* @deprecated use getActiveContextNote() instead
* @returns {NoteShort} active note (loaded into right pane)
*/
this.getActiveTabNote = () => {
console.warn("api.getActiveTabNote() is deprecated, use getActiveContextNote() instead.");
return appContext.tabManager.getActiveContextNote();
};
this.addTextToActiveTabEditor = text => appContext.triggerCommand('addTextToActiveEditor', {text});
/**
* @method
* @returns {NoteShort} active note (loaded into right pane)
*/
this.getActiveContextNote = () => appContext.tabManager.getActiveContextNote();
/**
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
*
* @deprecated use getActiveContextTextEditor()
* @method
* @param [callback] - callback receiving "textEditor" instance
*/
this.getActiveTabTextEditor = callback => {
console.warn("api.getActiveTabTextEditor() is deprecated, use getActiveContextTextEditor() instead.");
return appContext.tabManager.getActiveContext()?.getTextEditor(callback);
};
this.getActiveTabNote = () => appContext.tabManager.getActiveContextNote();
/**
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
*
* @method
* @returns {Promise&lt;CKEditor>} instance of CKEditor
* @param callback - method receiving "textEditor" instance
*/
this.getActiveContextTextEditor = () => appContext.tabManager.getActiveContext()?.getTextEditor();
/**
* See https://codemirror.net/doc/manual.html#api
*
* @method
* @returns {Promise&lt;CodeMirror>} instance of CodeMirror
*/
this.getActiveContextCodeEditor = () => appContext.tabManager.getActiveContext()?.getCodeEditor();
/**
* Get access to the widget handling note detail. Methods like `getWidgetType()` and `getTypeWidget()` to get to the
* implementation of actual widget type.
*
* @method
* @returns {Promise&lt;NoteDetailWidget>}
*/
this.getActiveNoteDetailWidget = () => new Promise(resolve => appContext.triggerCommand('executeInActiveNoteDetailWidget', {callback: resolve}));
/**
* @method
* @deprecated use getActiveContextNotePath() instead
* @returns {Promise&lt;string|null>} returns note path of active note or null if there isn't active note
*/
this.getActiveTabNotePath = () => {
console.warn("api.getActiveTabNotePath() is deprecated, use getActiveContextNotePath() instead.");
return appContext.tabManager.getActiveContextNotePath();
};
this.getActiveTabTextEditor = callback => appContext.triggerCommand('executeInActiveEditor', {callback});
/**
* @method
* @returns {Promise&lt;string|null>} returns note path of active note or null if there isn't active note
*/
this.getActiveContextNotePath = () => appContext.tabManager.getActiveContextNotePath();
/**
* Returns component which owns given DOM element (the nearest parent component in DOM tree)
*
* @method
* @param {Element} el - DOM element
* @returns {Component}
*/
this.getComponentByEl = el => appContext.getComponentByEl(el);
this.getActiveTabNotePath = () => appContext.tabManager.getActiveContextNotePath();
/**
* @method
@@ -486,26 +416,16 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
this.getTodayNote = dateNotesService.getTodayNote;
/**
* Returns day note for a given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise&lt;NoteShort>}
* @deprecated use getDayNote instead
*/
this.getDateNote = dateNotesService.getDayNote;
/**
* Returns day note for a given date. If it doesn't exist, it is automatically created.
* Returns date-note. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
* @return {Promise&lt;NoteShort>}
*/
this.getDayNote = dateNotesService.getDayNote;
this.getDateNote = dateNotesService.getDateNote;
/**
* Returns day note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
* Returns date-note for the first date of the week of the given date. If it doesn't exist, it is automatically created.
*
* @method
* @param {string} date - e.g. "2019-04-29"
@@ -550,10 +470,8 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
* @method
* @param {string} keyboardShortcut - e.g. "ctrl+shift+a"
* @param {function} handler
* @param {string} [namespace] - specify namespace of the handler for the cases where call for bind may be repeated.
* If a handler with this ID exists, it's replaced by the new handler.
*/
this.bindGlobalShortcut = shortcutService.bindGlobalShortcut;
this.bindGlobalShortcut = utils.bindGlobalShortcut;
/**
* Trilium runs in backend and frontend process, when something is changed on the backend from script,
@@ -581,33 +499,6 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain
* @returns {string} random string
*/
this.randomString = utils.randomString;
this.logMessages = {};
this.logSpacedUpdates = {};
/**
* Log given message to the log pane in UI
*
* @param message
*/
this.log = message => {
const {noteId} = this.startNote;
message = `${utils.now()}: ${message}`;
console.log(`Script ${noteId}: ${message}`);
this.logMessages[noteId] = this.logMessages[noteId] || [];
this.logSpacedUpdates[noteId] = this.logSpacedUpdates[noteId] || new SpacedUpdate(() => {
const messages = this.logMessages[noteId];
this.logMessages[noteId] = [];
appContext.triggerEvent("apiLogMessages", {noteId, messages});
}, 100);
this.logMessages[noteId].push(message);
this.logSpacedUpdates[noteId].scheduleUpdate();
};
}
export default FrontendScriptApi;
@@ -621,13 +512,13 @@ export default FrontendScriptApi;
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -37,9 +37,6 @@ const WIDGET_TPL = `
&lt;/div>
&lt;/div>`;
/**
* TODO: rename, it's not collapsible anymore
*/
export default class CollapsibleWidget extends NoteContextAwareWidget {
get widgetTitle() { return "Untitled widget"; }
@@ -48,7 +45,7 @@ export default class CollapsibleWidget extends NoteContextAwareWidget {
doRender() {
this.$widget = $(WIDGET_TPL);
this.contentSized();
this.$widget.find('[data-target]').attr('data-target', `#${this.componentId}`);
this.$widget.find('[data-target]').attr('data-target', "#" + this.componentId);
this.$bodyWrapper = this.$widget.find('.body-wrapper');
this.$bodyWrapper.attr('id', this.componentId); // for toggle to work we need id
@@ -63,6 +60,10 @@ export default class CollapsibleWidget extends NoteContextAwareWidget {
/** for overriding */
async doRenderBody() {}
isExpanded() {
return this.$bodyWrapper.hasClass("show");
}
}
</code></pre>
</article>
@@ -74,13 +75,13 @@ export default class CollapsibleWidget extends NoteContextAwareWidget {
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li><li><a href="module.exports.html">exports</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#doRenderBody">doRenderBody</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.0</a>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1,34 +0,0 @@
# Trilium Notes DB dump tool
This is a simple tool to dump the content of Trilium's document.db onto filesystem.
It is meant as a last resort solution when the standard mean to access your data (through main Trilium application) fail.
## Installation
This tool requires node.js, testing has been done on 16.18.0, but it will probably work on other versions as well.
```
npm install
```
## Running
See output of `node dump-db.js --help`:
```
dump-db.js <path_to_document> <target_directory>
dump the contents of document.db into the target directory
Positionals:
path_to_document path to the document.db
target_directory path of the directory into which the notes should be dumped
Options:
--help Show help [boolean]
--version Show version number [boolean]
--password Set password to be able to decrypt protected notes.[string]
--include-deleted If set to true, dump also deleted notes.
[boolean] [default: false]
```

View File

@@ -1,33 +0,0 @@
#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const dumpService = require("./inc/dump");
yargs(hideBin(process.argv))
.command('$0 <path_to_document> <target_directory>', 'dump the contents of document.db into the target directory', (yargs) => {
return yargs
.positional('path_to_document', { describe: 'path to the document.db' })
.positional('target_directory', { describe: 'path of the directory into which the notes should be dumped' })
}, (argv) => {
try {
dumpService.dumpDocument(argv.path_to_document, argv.target_directory, {
includeDeleted: argv.includeDeleted,
password: argv.password
});
}
catch (e) {
console.error(`Unrecoverable error:`, e);
process.exit(1);
}
})
.option('password', {
type: 'string',
description: 'Set password to be able to decrypt protected notes.'
})
.option('include-deleted', {
type: 'boolean',
default: false,
description: 'If set to true, dump also deleted notes.'
})
.parse();

View File

@@ -1,43 +0,0 @@
const crypto = require("crypto");
const sql = require("./sql");
const decryptService = require("./decrypt");
function getDataKey(password) {
if (!password) {
return null;
}
try {
const passwordDerivedKey = getPasswordDerivedKey(password);
const encryptedDataKey = getOption('encryptedDataKey');
const decryptedDataKey = decryptService.decrypt(passwordDerivedKey, encryptedDataKey, 16);
return decryptedDataKey;
}
catch (e) {
throw new Error(`Cannot read data key, the entered password might be wrong. The underlying error: '${e.message}', stack:\n${e.stack}`);
}
}
function getPasswordDerivedKey(password) {
const salt = getOption('passwordDerivedKeySalt');
return getScryptHash(password, salt);
}
function getScryptHash(password, salt) {
const hashed = crypto.scryptSync(password, salt, 32,
{N: 16384, r:8, p:1});
return hashed;
}
function getOption(name) {
return sql.getValue("SELECT value FROM options WHERE name = ?", [name]);
}
module.exports = {
getDataKey
};

Some files were not shown because too many files have changed in this diff Show More