Compare commits

..

68 Commits

Author SHA1 Message Date
azivner
cfa926602a release 0.25.0-beta 2018-12-02 00:30:07 +01:00
zadam
350cb52c07 Merge pull request #249 from nicoulaj/master
fix #248: crossorigin attribute is needed when including with type="module"
2018-12-02 00:27:59 +01:00
azivner
af195beb7e initial mac support + some other build changes 2018-12-02 00:26:45 +01:00
Julien Nicoulaud
cb00d42546 fix #248: crossorigin attribute is needed when including with type="module"
For more info, see:
 * https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
 * https://jakearchibald.com/2017/es-modules-in-browsers
2018-12-01 23:33:23 +01:00
azivner
ee0b0c3dfe minor export fixes 2018-11-30 22:43:03 +01:00
azivner
ddcb4a0e10 added another mime type for JS 2018-11-30 22:28:30 +01:00
azivner
8cbb29ee25 default location for data dir is now .local for linux and Roaming for windows 2018-11-30 19:56:20 +01:00
azivner
9da11ac144 electron 4 beta 8 2018-11-30 17:50:38 +01:00
azivner
ba7c8e77e5 add support for number precision in promoted attributes, closes #245 2018-11-30 17:36:41 +01:00
azivner
4577b03fc9 promoted attributes now use saved indicator (little check) instead of notification 2018-11-30 17:18:19 +01:00
azivner
72d83aa85e fix note cache - note entity after initialization doesn't contain ciphertext so decryption is not necessary 2018-11-30 15:51:55 +01:00
azivner
8ee80cb5f1 using dashes instead of underscores in header names to avoid the fact that nginx by default drops all headers with underscore in the header name 2018-11-30 15:49:35 +01:00
azivner
4cc08bff8b minor node updates in docker and server package 2018-11-30 13:56:36 +01:00
zadam
295cfb2d75 Merge pull request #247 from gabe565/master
Smaller Docker image
2018-11-30 13:38:47 +01:00
azivner
7775376b33 disable "cut to note" feature because of issues with CKEditor 2018-11-30 11:37:33 +01:00
azivner
9f64e994dc fix minor UI issue causing children overview not being decrypted right after entering protected session 2018-11-30 10:33:40 +01:00
azivner
ee1e4fc710 added "update pojo" stage in entity saving to avoid encrypting data on protected note directly on the entity 2018-11-30 10:20:03 +01:00
Gabe Cook
5ea62c710d Move devtron to devDependencies and update package-lock.json 2018-11-30 05:46:55 +00:00
Gabe Cook
aeca31d06a Add .git, bin, and docs to the .dockerignore 2018-11-30 05:46:49 +00:00
Gabe Cook
9cb9ea6ab5 Smaller Docker image by switching the base image to node:10.13.0-alpine and consolidating scripts 2018-11-30 05:41:53 +00:00
azivner
e37dd69827 link to Patterns of personal knowledge base 2018-11-28 22:05:23 +01:00
azivner
6c51696d1a also don't show "No results" for attr autocomplete 2018-11-27 19:43:34 +01:00
azivner
27787c8f37 attribute name and value autocompletes should not have autoselect since it's OK to enter value not in the autocomplete 2018-11-27 19:40:19 +01:00
azivner
e910595545 updated readme 2018-11-27 19:18:24 +01:00
azivner
a616739805 release 0.24.5 2018-11-27 15:34:15 +01:00
azivner
bea28de6a0 tab on autocomplete doesn't select first item, closes #243 2018-11-27 13:13:06 +01:00
azivner
4e198ca2f0 storing trilium version into export metadata 2018-11-27 10:31:55 +01:00
azivner
2fbd16a0e3 updated demo export according to latest format changes 2018-11-26 23:50:43 +01:00
azivner
76fc49f037 allow import of single HTML file too 2018-11-26 23:47:02 +01:00
azivner
139c99440f export stores note position and some other fixes 2018-11-26 23:39:43 +01:00
azivner
137b9dfa0b fix storing attributes and relinking noteIds 2018-11-26 23:19:19 +01:00
azivner
5f0fdd15eb fix adding sync entities during import 2018-11-26 22:37:59 +01:00
azivner
61e1427b83 fix matching of "b" in the note autcomplete highlighter 2018-11-26 22:35:19 +01:00
azivner
b3aa0ba47c entity events are not triggered on imported entities 2018-11-26 22:27:57 +01:00
azivner
56e2b44c25 fix import 2018-11-26 22:22:16 +01:00
azivner
4d5a17583f happy path tar import now works 2018-11-26 20:30:43 +01:00
azivner
71eda5aa3d import tar archive WIP 2018-11-26 14:47:46 +01:00
azivner
0711ea8dc8 filter out links and relations which are outside of the export 2018-11-25 22:38:09 +01:00
azivner
be206872d1 changed export model to single metadata file per exported .tar 2018-11-25 22:09:52 +01:00
azivner
fcf3fe8dcd tar export can now solve naming conflict 2018-11-25 15:17:28 +01:00
azivner
62dbd4062a on/off button for entering/leaving protected session has been changed to literal buttons 2018-11-25 14:12:33 +01:00
azivner
196e8b4380 extra icons 2018-11-25 14:05:54 +01:00
azivner
551e1255ff export WIP + some unrelated changes 2018-11-25 10:26:45 +01:00
azivner
e09b61d1ac single file export working, tar WIP 2018-11-24 20:58:38 +01:00
azivner
ee23bcc783 unified export dialog, WIP 2018-11-24 14:44:56 +01:00
azivner
3e351bd8d3 better positioning of nonmodal protected session dialog 2018-11-22 21:24:47 +01:00
azivner
0d3bc22d73 fix z-index of notification 2018-11-22 21:19:12 +01:00
azivner
d82898421e less obtrusive saved indicator, fixes #122 2018-11-22 20:25:49 +01:00
azivner
1db2f0c2c5 improved notifications, now with animations, in center and show up properly in the dialogs 2018-11-22 16:08:02 +01:00
azivner
6cd8a2203e create app icon only for electron build 2018-11-22 00:24:33 +01:00
azivner
08e062ab34 release 0.24.4-beta 2018-11-21 23:47:09 +01:00
azivner
3a06493459 partial workaround for the broken in page search (next & previous don't work, but at least highlighting works) 2018-11-21 23:39:19 +01:00
azivner
8159564885 fix .desktop + allow to turn this feature off 2018-11-21 11:19:33 +01:00
azivner
8ce3c1a480 generate local .desktop file so it shows among apps in linux desktop environments 2018-11-21 11:01:03 +01:00
azivner
dbc93f4a79 mitigations for tooltip flickering 2018-11-20 23:50:19 +01:00
azivner
92ffe321aa smaller context menu 2018-11-20 22:55:07 +01:00
azivner
6cb7d0098e changed layout a little bit to fix broken children overview in the electron/chrome 2018-11-20 22:49:10 +01:00
azivner
bdcb4361b2 simplification of note autocomplete result ordering by depth #240 2018-11-20 22:22:26 +01:00
azivner
15366d37d7 ordering results in autocomplete based on depth, closes #240 2018-11-20 21:22:20 +01:00
azivner
acd001501b release 0.24.3-beta 2018-11-20 13:01:41 +01:00
azivner
0019865807 disabling broken in page search 2018-11-20 12:54:03 +01:00
azivner
137ffcc4e3 enable line wrap for code editor 2018-11-20 10:49:03 +01:00
azivner
585398ad5c fix bug when saving non-text notes 2018-11-19 23:11:36 +01:00
azivner
50401954d1 disable cache for attribute name autocomplete 2018-11-19 22:17:08 +01:00
azivner
32a9df8489 fixes (and refactoring) for "empty attribute name" check 2018-11-19 22:06:51 +01:00
azivner
5bf5d1cac4 attribute dialog doesn't allow to (attempt to) save relation without target note 2018-11-19 21:58:52 +01:00
azivner
3608857f25 small fix to demo export 2018-11-19 21:09:59 +01:00
azivner
16a1dc12df jsdoc now doesn't include date into files to avoid unnecessary noise 2018-11-19 21:03:43 +01:00
114 changed files with 1805 additions and 991 deletions

View File

@@ -1,4 +1,7 @@
.git
.idea
/bin
/dist
/docs
/npm-debug.log
node_modules
npm-debug.log
dist
.idea

View File

@@ -1,21 +1,27 @@
FROM node:10.13.0
RUN apt-get update && apt-get install -y nasm
FROM node:10.14.0-alpine
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# Copy both package.json and package-lock.json
# where available (npm@5+)
COPY package*.json ./
COPY package.json package-lock.json ./
RUN npm install --production
# If you are building your code for production
# RUN npm install --only=production
# Install app dependencies
RUN set -x \
&& apk add --no-cache --virtual .build-dependencies \
autoconf \
automake \
g++ \
gcc \
libtool \
make \
nasm \
&& npm install --production \
&& apk del .build-dependencies
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "src/www" ]
CMD [ "node", "./src/www" ]

View File

@@ -1,23 +1,21 @@
# Trilium Notes
[![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 is a hierarchical note taking application. Picture tells a thousand words:
Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases. See [screenshots](https://github.com/zadam/trilium/wiki/Screenshot-tour) for quick overview:
![](https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png)
See other pictures in [screenshot tour](https://github.com/zadam/trilium/wiki/Screenshot-tour).
## Features
* Notes can be arranged into arbitrarily deep hierarchy (tree)
* Notes can have more than 1 parents - see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes)
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes))
* Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-editor#autoformat)
* Support for editing [notes with source code](https://github.com/zadam/trilium/wiki/Code-notes), including syntax highlighting
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation)
* 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
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes)
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) with per-note granularity
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-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)
* Scales well in both usability and performance upwards of 100 000 notes
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
@@ -25,16 +23,14 @@ See other pictures in [screenshot tour](https://github.com/zadam/trilium/wiki/Sc
## Builds
Trilium is provided as either desktop application ([Electron](https://electronjs.org)-based) or web application hosted on your server.
Trilium is provided as either desktop application (Linux, Windows) or web application hosted on your server (Linux). Mac is planned but not available at the moment.
* If you want to use Trilium on the desktop, download binary release for your platform (currently Linux and Windows are supported) from [latest release](https://github.com/zadam/trilium/releases/latest), unzip the package and run ```trilium``` executable.
* 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.
## Status
Trilium is beta quality software. While it is reasonably feature complete and is tested by its author, it lacks proper testing by more users. It's not yet recommended for daily use, but testing and experimentation is encouraged.
## Documentation
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
You can also read [Patterns of personal knowledge base](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base) to get some inspiration on how you might use Trilium.

View File

@@ -1,8 +1,5 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=`jq -r ".version" package.json`
sudo docker build -t zadam/trilium:latest -t zadam/trilium:$1 .
sudo docker build -t zadam/trilium:latest -t zadam/trilium:$VERSION .

19
bin/build-linux-ia32.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-linux-ia32
rm -rf $BUILD_DIR
echo "Rebuilding binaries for linux-ia32"
./node_modules/.bin/electron-rebuild --arch=ia32
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=ia32 --overwrite
mv "./dist/Trilium Notes-linux-ia32" $BUILD_DIR
rm -r $BUILD_DIR/resources/app/bin/deps
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
echo "Packaging linux ia32 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

20
bin/build-linux-x64.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-linux-x64
rm -rf $BUILD_DIR
# we build x64 as second so that we keep X64 binaries in node_modules for local development and server build
echo "Rebuilding binaries for linux-x64"
./node_modules/.bin/electron-rebuild --arch=x64
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
rm -r $BUILD_DIR/resources/app/bin/deps
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
echo "Packaging linux x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

27
bin/build-mac-x64.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-mac-x64
rm -rf $BUILD_DIR
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=src/public/images/app-icons/mac/icon.icns
# Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
echo "Copying required mac binaries"
MAC_RES_DIR=$BUILD_DIR/Trilium\ Notes.app/Contents/Resources/app
rm -r "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/*"
cp -r bin/deps/mac/sqlite/* "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/"
cp bin/deps/mac/image/cjpeg "$MAC_RES_DIR/node_modules/mozjpeg/vendor/"
cp bin/deps/mac/image/pngquant "$MAC_RES_DIR/node_modules/pngquant-bin/vendor/"
cp bin/deps/mac/image/gifsicle "$MAC_RES_DIR/node_modules/giflossy/vendor/"
rm -r "$MAC_RES_DIR/bin/deps"
echo "Packaging mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

View File

@@ -1,13 +1,7 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=$1
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=10.13.0
NODE_VERSION=10.14.1
rm -r $PKG_DIR
mkdir $PKG_DIR
@@ -35,4 +29,5 @@ chmod 755 trilium.sh
cd ..
VERSION=`jq -r ".version" package.json`
7z a trilium-linux-x64-server-${VERSION}.7z trilium-linux-x64-server

25
bin/build-win-x64.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-windows-x64
rm -rf $BUILD_DIR
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=src/public/images/app-icons/win/icon.ico
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
echo "Copying required windows binaries"
WIN_RES_DIR=$BUILD_DIR/resources/app
cp -r bin/deps/win/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/win/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/win/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/win/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
rm -r $WIN_RES_DIR/bin/deps
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
echo "Packaging windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

View File

@@ -8,36 +8,11 @@ echo "Deleting existing builds"
rm -r dist/*
echo "Rebuilding binaries for linux-ia32"
./node_modules/.bin/electron-rebuild --arch=ia32
bin/build-linux-ia32.sh
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=ia32 --overwrite
bin/build-win-x64.sh
mv "./dist/Trilium Notes-linux-ia32" ./dist/trilium-linux-ia32
bin/build-mac-x64.sh
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=src/public/images/app-icons/win/icon.ico
mv "./dist/Trilium Notes-win32-x64" ./dist/trilium-win32-x64
# we build x64 as second so that we keep X64 binaries in node_modules for local development and server build
echo "Rebuilding binaries for linux-x64"
./node_modules/.bin/electron-rebuild --arch=x64
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
mv "./dist/Trilium Notes-linux-x64" ./dist/trilium-linux-x64
echo "Copying required windows binaries"
WIN_RES_DIR=./dist/trilium-win32-x64/resources/app
cp -r bin/deps/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
echo "Cleaning up unnecessary binaries from all builds"
rm -r ./dist/trilium-linux-ia32/resources/app/bin/deps
rm -r ./dist/trilium-linux-x64/resources/app/bin/deps
rm -r ./dist/trilium-win32-x64/resources/app/bin/deps
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development
bin/build-linux-x64.sh

BIN
bin/deps/mac/image/cjpeg Normal file

Binary file not shown.

BIN
bin/deps/mac/image/gifsicle Normal file

Binary file not shown.

BIN
bin/deps/mac/image/pngquant Normal file

Binary file not shown.

0
bin/generate-cert.sh Normal file → Executable file
View File

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
VERSION=`jq -r ".version" package.json`
cd dist
echo "Packaging linux x64 electron distribution..."
7z a trilium-linux-x64-${VERSION}.7z trilium-linux-x64
echo "Packaging linux ia32 electron distribution..."
7z a trilium-linux-ia32-${VERSION}.7z trilium-linux-ia32
echo "Packaging windows x64 electron distribution..."
7z a trilium-windows-x64-${VERSION}.7z trilium-win32-x64

View File

@@ -42,18 +42,23 @@ git push origin $TAG
bin/build.sh
bin/package.sh
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.7z
LINUX_IA32_BUILD=trilium-linux-ia32-$VERSION.7z
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.7z
MAC_X64_BUILD=trilium-mac-x64-$VERSION.7z
SERVER_BUILD=trilium-linux-x64-server-$VERSION.7z
echo "Creating release in GitHub"
EXTRA=
if [[ $TAG == *"beta"* ]]; then
EXTRA=--pre-release
fi
github-release release \
--tag $TAG \
--name "$TAG release"
--name "$TAG release" $EXTRA
echo "Uploading linux x64 build"
@@ -76,6 +81,13 @@ github-release upload \
--name "$WINDOWS_X64_BUILD" \
--file "dist/$WINDOWS_X64_BUILD"
echo "Uploading mac x64 build"
github-release upload \
--tag $TAG \
--name "$MAC_X64_BUILD" \
--file "dist/$MAC_X64_BUILD"
echo "Packaging server version"
bin/build-server.sh $VERSION

Binary file not shown.

View File

@@ -0,0 +1 @@
UPDATE attributes SET name = 'archived' where name = 'hideInAutocomplete';

View File

@@ -288,7 +288,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -730,7 +730,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -3814,7 +3814,7 @@ transactional by default.
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -511,7 +511,7 @@ Each note can have multiple (at least one) branches, meaning it can be placed in
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -216,7 +216,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -358,7 +358,7 @@ this is different concept than attribute/relation.</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -7297,7 +7297,7 @@ Cache is note instance scoped.
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -403,7 +403,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -311,7 +311,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -288,7 +288,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -75,7 +75,7 @@ module.exports = ApiToken;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -151,7 +151,7 @@ module.exports = Attribute;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -105,7 +105,7 @@ module.exports = Branch;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -93,7 +93,7 @@ module.exports = Entity;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -92,7 +92,7 @@ module.exports = Link;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -651,7 +651,7 @@ module.exports = Note;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -91,7 +91,7 @@ module.exports = NoteRevision;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -78,7 +78,7 @@ module.exports = Option;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -75,7 +75,7 @@ module.exports = RecentNote;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -594,7 +594,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -56,7 +56,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -278,7 +278,7 @@ module.exports = BackendScriptApi;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -719,7 +719,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -2846,7 +2846,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -279,7 +279,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -1316,7 +1316,7 @@ Its notable omission is the note content.</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -76,7 +76,7 @@ export default Branch;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -64,7 +64,7 @@ export default NoteFull;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -128,7 +128,7 @@ export default NoteShort;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -339,7 +339,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -56,7 +56,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -271,7 +271,7 @@ export default FrontendScriptApi;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -6,6 +6,7 @@ const log = require('./src/services/log');
const cls = require('./src/services/cls');
const url = require("url");
const port = require('./src/services/port');
const appIconService = require('./src/services/app_icon');
const app = electron.app;
const globalShortcut = electron.globalShortcut;
@@ -13,6 +14,8 @@ const globalShortcut = electron.globalShortcut;
// Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
appIconService.installLocalAppIcon();
// Prevent window being garbage collected
let mainWindow;

7
jsdoc-conf.json Normal file
View File

@@ -0,0 +1,7 @@
{
"templates": {
"default": {
"includeDate": false
}
}
}

315
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.24.1-beta",
"version": "0.24.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -65,21 +65,21 @@
}
},
"@jimp/bmp": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.5.4.tgz",
"integrity": "sha512-P/ezH1FuoM3FwS0Dm2ZGkph4x5/rPBzFLEZor7KQkmGUnYEIEG4o0BUcAWFmJOp2HgzbT6O2SfrpJNBOcVACzQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.6.0.tgz",
"integrity": "sha512-zZOcVT1zK/1QL5a7qirkzPPgDKB1ianER7pBdpR2J71vx/g8MnrPbL3h/jEVPxjdci2Hph/VWhc/oLBtTbqO8w==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"bmp-js": "^0.1.0",
"core-js": "^2.5.7"
}
},
"@jimp/core": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.5.4.tgz",
"integrity": "sha512-n3uvHy2ndUKItmbhnRO8xmU8J6KR+v6CQxO9sbeUDpSc3VXc1PkqrA8ZsCVFCjnDFcGBXL+MJeCTyQzq5W9Crw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.6.0.tgz",
"integrity": "sha512-ngAkyCLtX7buc2QyFy0ql/j4R2wGYQVsVhW2G3Y0GVAAklRIFIUYpyNKrqs228xA8f2O6XStbDStFlYkt7uNeg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"any-base": "^1.1.0",
"buffer": "^5.2.0",
"core-js": "^2.5.7",
@@ -114,252 +114,252 @@
}
},
"@jimp/custom": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.5.4.tgz",
"integrity": "sha512-tLfyJoyouDl2J3RPFGfDzTtE+4S8ljqJUmLzy/cmx1n7+xS5TpLPdPskp7UaeAfNTqdF4CNAm94KYoxTZdj2mg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.6.0.tgz",
"integrity": "sha512-+YZIWhf03Rfbi+VPbHomKInu3tcntF/aij/JrIJd1QZq13f8m3mRNxakXupiL18KH0C8BPNDk8RiwFX+HaOw3A==",
"requires": {
"@jimp/core": "^0.5.4",
"@jimp/core": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/gif": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.5.0.tgz",
"integrity": "sha512-HVB4c7b8r/yCpjhCjVNPRFLuujTav5UPmcQcFJjU6aIxmne6e29rAjRJEv3UMamHDGSu/96PzOsPZBO5U+ZGww==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.6.0.tgz",
"integrity": "sha512-aWQ02P0ymTN1eh0BVsY+84wMdb/QeiVpCNQZl9y50cRnpuMM8TTmF/ZdCEBDiTRFcwXzHsqBXcLwEcYp3X2lTw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"omggif": "^1.0.9"
}
},
"@jimp/jpeg": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.5.4.tgz",
"integrity": "sha512-YaPWm+YSGCThNE/jLMckM3Qs6uaMxd/VsHOnEaqu5tGA4GFbfVaWHjKqkNGAFuiNV+HdgKlNcCOF3of+elvzqQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.6.0.tgz",
"integrity": "sha512-quYb+lM4h57jQvr2q9dEIkc0laTljws4dunIdFhJRfa5UlNL5mHInk8h5MxyALo0mZdT07TAcxiDHw5QXZ28JQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"jpeg-js": "^0.3.4"
}
},
"@jimp/plugin-blit": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.5.4.tgz",
"integrity": "sha512-WqDYOugv76hF1wnKy7+xPGf9PUbcm9vPW28/jHWn1hjbb2GnusJ2fVEFad76J/1SPfhrQ2Uebf2QCWJuLmOqZg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.6.0.tgz",
"integrity": "sha512-LjiCa+8OT2fgmvBpZt0ogurg/eu5kB8ZFWDRwHPcf8i+058sZC20dar/qrjVd5Knssq4ynjb5oAHsGuJq16Rqw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-blur": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.5.0.tgz",
"integrity": "sha512-5k0PXCA1RTJdITL7yMAyZ5tGQjKLHqFvwdXj/PCoBo5PuMyr0x6qfxmQEySixGk/ZHdDxMi80vYxHdKHjNNgjg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.6.0.tgz",
"integrity": "sha512-/vjGcEiHda6OLTCYqXPFkfSTbL+RatZoGcp1vewcWqChUccn9QVINTlxB7nEI/3Nb/i7KdhOPNEQh1k6q6QXsw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-color": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.5.5.tgz",
"integrity": "sha512-hWeOqNCmLguGYLhSvBrpfCvlijsMEVaLZAOod62s1rzWnujozyKOzm2eZe+W3To6mHbp5RGJNVrIwHBWMab4ug==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.6.0.tgz",
"integrity": "sha512-mvDeAwN8ZpDkOaABMJ0w9zUzo9OOtu1qvvPkSirXDTMiXt1nsbfz8BoeoD7nU2MFhQj5MiGjH65UDnsH5ZzYuw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"tinycolor2": "^1.4.1"
}
},
"@jimp/plugin-contain": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.5.4.tgz",
"integrity": "sha512-8YJh4FI3S69unri0nJsWeqVLeVGA77N2R0Ws16iSuCCD/5UnWd9FeWRrSbKuidBG6TdMBaG2KUqSYZeHeH9GOQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.6.0.tgz",
"integrity": "sha512-gPHnoQkDztMbvnTVo01BaMoM/hhDJdeJ7FRToD4p4Qvdor4V0I6NXtjOeUPXfD94miTgh/UTyJDqeG4GZzi4sA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-cover": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.5.4.tgz",
"integrity": "sha512-2Rur7b44WiDDgizUI2M2uYWc1RmfhU5KjKS1xXruobjQ0tXkf5xlrPXSushq0hB6Ne0Ss6wv0+/6eQ8WeGHU2w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.6.0.tgz",
"integrity": "sha512-iv9lA2v3qv+x3eaTThtyzFg+hO8/pSnM8NBymC5OlpSJnR54aWi7BVFXLJAF27T4EZyXko432PVul2IdY3BEPw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-crop": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.5.4.tgz",
"integrity": "sha512-6t0rqn4VazquGk48tO6hFBrQ+nkvC+A1RnR6UM/m8ZtG2/yjpwF0MXcpgJI1Fb+a4Ug7BY1fu2GPcZOhnAVK/g==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.6.0.tgz",
"integrity": "sha512-YftdmFZ2YnZDYyBulkStCt2MZbKKfbjytkE+6i3Djk2b/Rfryg5xjgzVnAumCRQJhVPukexrnc2V7KKbEgx7mQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-displace": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.5.0.tgz",
"integrity": "sha512-Bec7SQvnmKia4hOXEDjeNVx7vo/1bWqjuV6NO8xbNQcAO3gaCl91c9FjMDhsfAVb0Ou6imhbIuFPrLxorXsecQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.6.0.tgz",
"integrity": "sha512-kkva5Fy3r7J7QmiqYQ5c9NeUKKkN7+KSfCGsZ6tkRHK4REMIXhQO/OnJN8XG6RReV29O6QykdyeTXDiHUDiROw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-dither": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.5.0.tgz",
"integrity": "sha512-We2WJQsD/Lm8oqBFp/vUv9/5r2avyenL+wNNu/s2b1HqA5O4sPGrjHy9K6vIov0NroQGCQ3bNznLkTmjiHKBcg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.6.0.tgz",
"integrity": "sha512-ILSG7bl3SOqmcIa9C4nBvs0h0E0ObnMbeKWUZiNuz6i0OAlbxryiIfU4j0UVQD5XqT9ksC5mviVNrvOMw4SZLw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-flip": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.5.0.tgz",
"integrity": "sha512-D/ehBQxLMNR7oNd80KXo4tnSET5zEm5mR70khYOTtTlfti/DlLp3qOdjPOzfLyAdqO7Ly4qCaXrIsnia+pfPrA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.6.0.tgz",
"integrity": "sha512-MXGGwABjERvfqVadEzJuVAmbsEQfjxXD0O/mMBegU1Qh7/JmnKAVplQCnojsMPxUdao/FKZjQqOnB/j4LLJtOQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-gaussian": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.5.0.tgz",
"integrity": "sha512-Ln4kgxblv0/YzLBDb/J8DYPLhDzKH87Y8yHh5UKv3H+LPKnLaEG3L4iKTE9ivvdocnjmrtTFMYcWv2ERSPeHcg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.6.0.tgz",
"integrity": "sha512-RUsBCyj6Ukxgn/TU8v6c6WRbSFqKM0iknLVqDkKIuiOyJB7ougv66fqomh/i/h3ihIkEnf50BuO0c3ovrczfvw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-invert": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.5.0.tgz",
"integrity": "sha512-/vyKeIi3T7puf+8ruWovTjzDC585EnTwJ+lGOOUYiNPsdn4JDFe1B3xd+Ayv9aCQbXDIlPElZaM9vd/+wqDiIQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.6.0.tgz",
"integrity": "sha512-zTCqK8el6eqcNKAxw0y57gHBFgxygI5iM8dQDPyqsvVWO71i8XII7ubnJhEvPPN7vhIKlOSnS9XXglezvJoX4Q==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-mask": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.5.4.tgz",
"integrity": "sha512-mUJ04pCrUWaJGXPjgoVbzhIQB8cVobj2ZEFlGO3BEAjyylYMrdJlNlsER8dd7UuJ2L/a4ocWtFDdsnuicnBghQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.6.0.tgz",
"integrity": "sha512-zkZVqAA7lxWhkn5EbPjBQ6tPluYIGfLMSX4kD1gksj+MVJJnVAd459AVuEXCvkUvv4wG5AlH8m6ve5NZj9vvxw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-normalize": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.5.4.tgz",
"integrity": "sha512-Q5W0oEz9wxsjuhvHAJynI/OqXZcmqEAuRONQId7Aw5ulCXSOg9C4y2a67EO7aZAt55T+zMVxI9UpVUpzVvO6hw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.6.0.tgz",
"integrity": "sha512-7bNGT+S0rw9gvmxpkNsA19JSqBZYFrAn9QhEmoN4HIimdKtJaoLJh/GnxrPuOBLuv1IPJntoTOOWvOmfrQ6/ww==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-print": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.5.4.tgz",
"integrity": "sha512-DOZr5TY9WyMWFBD37oz7KpTEBVioFIHQF/gH5b3O5jjFyj4JPMkw7k3kVBve9lIrzIYrvLqe0wH59vyAwpeEFg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.6.0.tgz",
"integrity": "sha512-kXNHYo7bGQiMZkUqhCvm6OomjJtZnLGs7cgXp9qsCfPcDBLLW+X3oxnoLaePQMlpQt6hX/lzFnNaWKv/KB1jlA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"load-bmfont": "^1.4.0"
}
},
"@jimp/plugin-resize": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.5.4.tgz",
"integrity": "sha512-lXNprNAT0QY1D1vG/1x6urUTlWuZe2dfL29P81ApW2Yfcio471+oqo45moX5FLS0q24xU600g7cHGf2/TzqSfA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.6.0.tgz",
"integrity": "sha512-m0AA/mPkJG++RuftBFDUMRenqgIN/uSh88Kqs33VURYaabApni4ML3QslE1TCJtl2Lnu1eosxYlbzODjHx49eg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-rotate": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.5.4.tgz",
"integrity": "sha512-SIdUpMc8clObMchy8TnjgHgcXEQM992z5KavgiuOnCuBlsmSHtE3MrXTOyMW0Dn3gqapV9Y5vygrLm/BVtCCsg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.6.0.tgz",
"integrity": "sha512-1QGlIisyxs2HNLuynq/ETc4h7E6At3yR+IYAhG9U4KONG4RqlIy0giyDhnfEZaiqOE+O7f+0Z7zN6GoSHmQjzg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-scale": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.5.0.tgz",
"integrity": "sha512-5InIOr3cNtrS5aQ/uaosNf28qLLc0InpNGKFmGFTv8oqZqLch6PtDTjDBZ1GGWsPdA/ljy4Qyy7mJO1QBmgQeQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.6.0.tgz",
"integrity": "sha512-le/ttYwYioNPRoMlMaoJMCTv+m8d1v0peo/3J8E6Rf9ok7Bw3agkvjL9ILnsmr8jXj1YLrBSPKRs5nJ6ziM/qA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugins": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.5.5.tgz",
"integrity": "sha512-9oF6LbSM/K7YkFCcxaPaD8NUkL/ZY8vT8NIGfQ/NpX+tKQtcsLHcRavHpUC+M1xXShv/QGx9OdBV/jgiu82QYg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.6.0.tgz",
"integrity": "sha512-9+znfBJM1B31kvw+IcQFnAuDntQhwca/SONFnKOSZ8BNiQdiuTNbXHFxOo3tvdv1ngtB+LkkiTgK+QoF358b8g==",
"requires": {
"@jimp/plugin-blit": "^0.5.4",
"@jimp/plugin-blur": "^0.5.0",
"@jimp/plugin-color": "^0.5.5",
"@jimp/plugin-contain": "^0.5.4",
"@jimp/plugin-cover": "^0.5.4",
"@jimp/plugin-crop": "^0.5.4",
"@jimp/plugin-displace": "^0.5.0",
"@jimp/plugin-dither": "^0.5.0",
"@jimp/plugin-flip": "^0.5.0",
"@jimp/plugin-gaussian": "^0.5.0",
"@jimp/plugin-invert": "^0.5.0",
"@jimp/plugin-mask": "^0.5.4",
"@jimp/plugin-normalize": "^0.5.4",
"@jimp/plugin-print": "^0.5.4",
"@jimp/plugin-resize": "^0.5.4",
"@jimp/plugin-rotate": "^0.5.4",
"@jimp/plugin-scale": "^0.5.0",
"@jimp/plugin-blit": "^0.6.0",
"@jimp/plugin-blur": "^0.6.0",
"@jimp/plugin-color": "^0.6.0",
"@jimp/plugin-contain": "^0.6.0",
"@jimp/plugin-cover": "^0.6.0",
"@jimp/plugin-crop": "^0.6.0",
"@jimp/plugin-displace": "^0.6.0",
"@jimp/plugin-dither": "^0.6.0",
"@jimp/plugin-flip": "^0.6.0",
"@jimp/plugin-gaussian": "^0.6.0",
"@jimp/plugin-invert": "^0.6.0",
"@jimp/plugin-mask": "^0.6.0",
"@jimp/plugin-normalize": "^0.6.0",
"@jimp/plugin-print": "^0.6.0",
"@jimp/plugin-resize": "^0.6.0",
"@jimp/plugin-rotate": "^0.6.0",
"@jimp/plugin-scale": "^0.6.0",
"core-js": "^2.5.7",
"timm": "^1.6.1"
}
},
"@jimp/png": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.5.4.tgz",
"integrity": "sha512-J2NU7368zihF1HUZdmpXsL/Hhyf+I3ubmK+6Uz3Uoyvtk1VS7dO3L0io6fJQutfWmPZ4bvu6Ry022oHjbi6QCA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.6.0.tgz",
"integrity": "sha512-DBtMyQyrJxuKI7/1dVqLek+rCMM8U6BSOTHgo05wU7lhJKTB6fn2tbYfsnHQKzd9ld1M2qKuC+O1GTVdB2yl6w==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"pngjs": "^3.3.3"
}
},
"@jimp/tiff": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.5.4.tgz",
"integrity": "sha512-hr7Zq3eWjAZ+itSwuAObIWMRNv7oHVM3xuEDC2ouP7HfE7woBtyhCyfA7u12KlgtM57gKWeogXqTlewRGVzx6g==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.6.0.tgz",
"integrity": "sha512-PV95CquEsolFziq0zZrAEJIzZSKwMK89TvkOXTPDi/xesgdXGC2rtG1IZFpC9L4UX5hi/M5GaeJa49xULX6Nqw==",
"requires": {
"core-js": "^2.5.7",
"utif": "^2.0.1"
}
},
"@jimp/types": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.5.4.tgz",
"integrity": "sha512-nbZXM6TsdpnYHIBd8ZuoxGpvmxc2SqiggY30/bhOP/VJQoDBzm2v/20Ywz5M0snpIK2SdYG52eZPNjfjqUP39w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.6.0.tgz",
"integrity": "sha512-j4tm82huEWpLrwave/2NYnMTY6us/6K9Js6Vd/CHoM/ki8M71tMXEVzc8tly92wtnEzQ9+FEk0Ue6pYo68m/5A==",
"requires": {
"@jimp/bmp": "^0.5.4",
"@jimp/gif": "^0.5.0",
"@jimp/jpeg": "^0.5.4",
"@jimp/png": "^0.5.4",
"@jimp/tiff": "^0.5.4",
"@jimp/bmp": "^0.6.0",
"@jimp/gif": "^0.6.0",
"@jimp/jpeg": "^0.6.0",
"@jimp/png": "^0.6.0",
"@jimp/tiff": "^0.6.0",
"core-js": "^2.5.7",
"timm": "^1.6.1"
}
},
"@jimp/utils": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.5.0.tgz",
"integrity": "sha512-7H9RFVU+Li2XmEko0GGyzy7m7JjSc7qa+m8l3fUzYg2GtwASApjKF/LSG2AUQCUmDKFLdfIEVjxvKvZUJFEmpw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.6.0.tgz",
"integrity": "sha512-z5iYEfqc45vlYweROneNkjv32en6jS7lPL/eMLIvaEcQAHaoza20Dw8fUoJ0Ht9S92kR74xeTunAZq+gK2w67Q==",
"requires": {
"core-js": "^2.5.7"
}
@@ -399,9 +399,9 @@
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow=="
},
"@types/node": {
"version": "8.10.37",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.37.tgz",
"integrity": "sha512-Jp39foY8Euv/PG4OGPyzxis82mnjcUtXLEMA8oFMCE4ilmuJgZPdV2nZNV1moz+99EJTtcpOSgDCgATUwABKig==",
"version": "8.10.38",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.38.tgz",
"integrity": "sha512-EibsnbJerd0hBFaDjJStFrVbVBAtOy4dgL8zZFw0uOvPqzBAX59Ci8cgjg3+RgJIWhsB5A4c+pi+D4P9tQQh/A==",
"dev": true
},
"abab": {
@@ -426,7 +426,8 @@
"accessibility-developer-tools": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz",
"integrity": "sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ="
"integrity": "sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=",
"dev": true
},
"acorn": {
"version": "5.7.3",
@@ -2202,6 +2203,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/devtron/-/devtron-1.4.0.tgz",
"integrity": "sha1-tedIvW6Vu+cL/MaKrm/mlhGUQeE=",
"dev": true,
"requires": {
"accessibility-developer-tools": "^2.11.0",
"highlight.js": "^9.3.0",
@@ -2372,9 +2374,9 @@
"integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ=="
},
"electron": {
"version": "4.0.0-beta.7",
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.0-beta.7.tgz",
"integrity": "sha512-770Hzxq10nQrzq39uVmvHLNKpPY3TCNrk+IYGDQTNWqmkreXZX6+9iflMMo+xdg1ZHysrTj1QQZvsjjBY176pg==",
"version": "4.0.0-beta.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.0-beta.8.tgz",
"integrity": "sha512-zo0Tf3t1uary5O9Skdlo37axs+vvh9CPC+MkvZnnX3MA/3kWIc+I6jN+AL4bHUdxsMVtjbY8KnusjnCjKSb0sg==",
"dev": true,
"requires": {
"@types/node": "^8.0.24",
@@ -4903,7 +4905,8 @@
"highlight.js": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=",
"dev": true
},
"hosted-git-info": {
"version": "2.7.1",
@@ -4965,7 +4968,8 @@
"humanize-plus": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz",
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA="
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=",
"dev": true
},
"iconv-lite": {
"version": "0.4.23",
@@ -5750,14 +5754,14 @@
"dev": true
},
"jimp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.5.6.tgz",
"integrity": "sha512-H0nHTu6KgAgQzDxa38ew2dXbnRzKm1w5uEyhMIxqwCQVjwgarOjjkV/avbNLxfxRHAFaNp4rGIc/qm8P+uhX9A==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.6.0.tgz",
"integrity": "sha512-RYpN+AAlTEMf8Bnkhq2eeTNyr70rDK/2UUfUqzBJmwmZwdR6fxRJvgbCGWT1BDVRxaAqo+4CWm8ePBxOIsr4jg==",
"requires": {
"@babel/polyfill": "^7.0.0",
"@jimp/custom": "^0.5.4",
"@jimp/plugins": "^0.5.5",
"@jimp/types": "^0.5.4",
"@jimp/custom": "^0.6.0",
"@jimp/plugins": "^0.6.0",
"@jimp/types": "^0.6.0",
"core-js": "^2.5.7"
}
},
@@ -6417,11 +6421,18 @@
"integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw=="
},
"mime-types": {
"version": "2.1.20",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz",
"integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==",
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"requires": {
"mime-db": "~1.36.0"
"mime-db": "~1.37.0"
},
"dependencies": {
"mime-db": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
}
}
},
"mimic-fn": {
@@ -7770,9 +7781,9 @@
}
},
"pako": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
"integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.7.tgz",
"integrity": "sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ=="
},
"parse-author": {
"version": "2.0.0",
@@ -10821,9 +10832,9 @@
}
},
"ws": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz",
"integrity": "sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz",
"integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==",
"requires": {
"async-limiter": "~1.0.0"
}

View File

@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.24.2-beta",
"version": "0.25.0-beta",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -15,8 +15,8 @@
"scripts": {
"start": "node ./src/www",
"start-electron": "electron . --disable-gpu",
"build-backend-docs": "jsdoc -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
"build-frontend-docs": "jsdoc -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
"build-backend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
"build-frontend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs"
},
"dependencies": {
@@ -27,7 +27,6 @@
"commonmark": "0.28.1",
"cookie-parser": "1.4.3",
"debug": "4.1.0",
"devtron": "1.4.0",
"ejs": "2.6.1",
"electron-debug": "2.0.0",
"electron-dl": "1.12.0",
@@ -44,7 +43,8 @@
"imagemin-mozjpeg": "8.0.0",
"imagemin-pngquant": "6.0.0",
"ini": "1.3.5",
"jimp": "0.5.6",
"jimp": "0.6.0",
"mime-types": "^2.1.21",
"moment": "2.22.2",
"multer": "1.4.1",
"open": "0.0.5",
@@ -62,11 +62,12 @@
"tar-stream": "1.6.2",
"turndown": "5.0.1",
"unescape": "1.0.1",
"ws": "6.1.0",
"ws": "6.1.2",
"xml2js": "0.4.19"
},
"devDependencies": {
"electron": "4.0.0-beta.7",
"devtron": "1.4.0",
"electron": "4.0.0-beta.8",
"electron-compile": "6.4.3",
"electron-packager": "12.2.0",
"electron-rebuild": "1.8.2",

View File

@@ -105,6 +105,11 @@ class Attribute extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.isOwned;
}
}
module.exports = Attribute;

View File

@@ -59,6 +59,11 @@ class Branch extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.origParentNoteId;
}
}
module.exports = Branch;

View File

@@ -4,6 +4,7 @@ const Entity = require('./entity');
const Attribute = require('./attribute');
const protectedSessionService = require('../services/protected_session');
const repository = require('../services/repository');
const sql = require('../services/sql');
const dateUtils = require('../services/date_utils');
const LABEL = 'label';
@@ -74,7 +75,9 @@ class Note extends Entity {
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript() {
return (this.type === "code" || this.type === "file")
&& (this.mime.startsWith("application/javascript") || this.mime === "application/x-javascript");
&& (this.mime.startsWith("application/javascript")
|| this.mime === "application/x-javascript"
|| this.mime === "text/javascript");
}
/** @returns {boolean} true if this note is HTML */
@@ -433,14 +436,32 @@ class Note extends Entity {
}
/**
* Finds child notes with given attribute name and value. Only own attributes are considered, not inherited ones
* @return {Promise<string[]>} return list of all descendant noteIds of this note. Returning just noteIds because number of notes can be huge. Includes also this note's noteId
*/
async getDescendantNoteIds() {
return await sql.getColumn(`
WITH RECURSIVE
tree(noteId) AS (
SELECT ?
UNION
SELECT branches.noteId FROM branches
JOIN tree ON branches.parentNoteId = tree.noteId
JOIN notes ON notes.noteId = branches.noteId
WHERE notes.isDeleted = 0
AND branches.isDeleted = 0
)
SELECT noteId FROM tree`, [this.noteId]);
}
/**
* Finds descendant notes with given attribute name and value. Only own attributes are considered, not inherited ones
*
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @param {string} [value] - attribute value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithAttribute(type, name, value) {
async getDescendantNotesWithAttribute(type, name, value) {
const params = [this.noteId, name];
let valueCondition = "";
@@ -472,22 +493,22 @@ class Note extends Entity {
}
/**
* Finds notes with given label name and value. Only own labels are considered, not inherited ones
* Finds descendant notes with given label name and value. Only own labels are considered, not inherited ones
*
* @param {string} name - label name
* @param {string} [value] - label value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithLabel(name, value) { return await this.findChildNotesWithAttribute(LABEL, name, value); }
async getDescendantNotesWithLabel(name, value) { return await this.getDescendantNotesWithAttribute(LABEL, name, value); }
/**
* Finds notes with given relation name and value. Only own relations are considered, not inherited ones
* Finds descendant notes with given relation name and value. Only own relations are considered, not inherited ones
*
* @param {string} name - relation name
* @param {string} [value] - relation value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithRelation(name, value) { return await this.findChildNotesWithAttribute(RELATION, name, value); }
async getDescendantNotesWithRelation(name, value) { return await this.getDescendantNotesWithAttribute(RELATION, name, value); }
/**
* Returns note revisions of this note.
@@ -587,10 +608,6 @@ class Note extends Entity {
// we do this here because encryption needs the note ID for the IV
this.generateIdIfNecessary();
if (this.isProtected) {
protectedSessionService.encryptNote(this);
}
if (!this.isDeleted) {
this.isDeleted = false;
}
@@ -605,6 +622,17 @@ class Note extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
if (pojo.isProtected) {
protectedSessionService.encryptNote(pojo);
}
delete pojo.jsonContent;
delete pojo.isContentAvailable;
delete pojo.__attributeCache;
}
}
module.exports = Note;

Binary file not shown.

View File

@@ -67,7 +67,8 @@ function AttributesModel() {
attr.labelDefinition = (attr.type === 'label-definition' && attr.value) ? attr.value : {
labelType: "text",
multiplicityType: "singlevalue",
isPromoted: true
isPromoted: true,
numberPrecision: 0
};
attr.relationDefinition = (attr.type === 'relation-definition' && attr.value) ? attr.value : {
@@ -114,7 +115,7 @@ function AttributesModel() {
function isValid() {
for (let attributes = self.ownedAttributes(), i = 0; i < attributes.length; i++) {
if (self.isEmptyName(i)) {
if (self.isEmptyName(i) || self.isEmptyRelationTarget(i)) {
return false;
}
}
@@ -187,7 +188,8 @@ function AttributesModel() {
labelDefinition: {
labelType: "text",
multiplicityType: "singlevalue",
isPromoted: true
isPromoted: true,
numberPrecision: 0
},
relationDefinition: {
multiplicityType: "singlevalue",
@@ -209,7 +211,35 @@ function AttributesModel() {
this.isEmptyName = function(index) {
const cur = self.ownedAttributes()[index]();
return cur.name.trim() === "" && !cur.isDeleted && (cur.attributeId !== "" || cur.labelValue !== "" || cur.relationValue);
if (cur.name.trim() || cur.isDeleted) {
return false;
}
if (cur.attributeId) {
// name is empty and attribute already exists so this is NO-GO
return true;
}
if (cur.type === 'relation-definition' || cur.type === 'label-definition') {
// for definitions there's no possible empty value so we always require name
return true;
}
if (cur.type === 'label' && cur.labelValue) {
return true;
}
if (cur.type === 'relation' && cur.relationValue) {
return true;
}
return false;
};
this.isEmptyRelationTarget = function(index) {
const cur = self.ownedAttributes()[index]();
return cur.type === "relation" && !cur.isDeleted && cur.name && !cur.relationValue;
};
this.getTargetAttribute = function(target) {

View File

@@ -0,0 +1,77 @@
import treeService from '../services/tree.js';
import treeUtils from "../services/tree_utils.js";
import exportService from "../services/export.js";
const $dialog = $("#export-dialog");
const $form = $("#export-form");
const $noteTitle = $dialog.find(".note-title");
const $subtreeFormats = $("#export-subtree-formats");
const $singleFormats = $("#export-single-formats");
const $subtreeType = $("#export-type-subtree");
const $singleType = $("#export-type-single");
async function showDialog(defaultType) {
if (defaultType === 'subtree') {
$subtreeType.prop("checked", true).change();
}
else if (defaultType === 'single') {
$singleType.prop("checked", true).change();
}
else {
throw new Error("Unrecognized type " + defaultType);
}
glob.activeDialog = $dialog;
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
}
$form.submit(() => {
const exportType = $dialog.find("input[name='export-type']:checked").val();
if (!exportType) {
// this shouldn't happen as we always choose default export type
alert("Choose export type first please");
return;
}
const exportFormat = exportType === 'subtree'
? $("input[name=export-subtree-format]:checked").val()
: $("input[name=export-single-format]:checked").val();
const currentNode = treeService.getCurrentNode();
exportService.exportBranch(currentNode.data.branchId, exportType, exportFormat);
$dialog.modal('hide');
return false;
});
$('input[name=export-type]').change(function () {
if (this.value === 'subtree') {
if ($("input[name=export-subtree-format]:checked").length === 0) {
$("input[name=export-subtree-format]:first").prop("checked", true);
}
$subtreeFormats.slideDown();
$singleFormats.slideUp();
}
else {
if ($("input[name=export-single-format]:checked").length === 0) {
$("input[name=export-single-format]:first").prop("checked", true);
}
$subtreeFormats.slideUp();
$singleFormats.slideDown();
}
});
export default {
showDialog
};

View File

@@ -1,35 +0,0 @@
import treeService from '../services/tree.js';
import server from '../services/server.js';
import treeUtils from "../services/tree_utils.js";
import exportService from "../services/export.js";
const $dialog = $("#export-subtree-dialog");
const $form = $("#export-subtree-form");
const $noteTitle = $dialog.find(".note-title");
async function showDialog() {
glob.activeDialog = $dialog;
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
}
$form.submit(() => {
const exportFormat = $dialog.find("input[name='export-format']:checked").val();
const currentNode = treeService.getCurrentNode();
exportService.exportSubtree(currentNode.data.branchId, exportFormat);
$dialog.modal('hide');
return false;
});
export default {
showDialog
};

View File

@@ -14,7 +14,7 @@ class Branch {
/** @param {string} */
this.prefix = row.prefix;
/** @param {boolean} */
this.isExpanded = row.isExpanded;
this.isExpanded = !!row.isExpanded;
}
/** @returns {NoteShort} */

View File

@@ -10,11 +10,13 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
$el.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'name',
// disabling cache is important here because otherwise cache can stay intact when switching between attribute type which will lead to autocomplete displaying attribute names for incorrect attribute type
cache: false,
source: async (term, cb) => {
const type = typeof attributeType === "function" ? attributeType() : attributeType;
@@ -23,10 +25,6 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
return {name};
});
if (result.length === 0) {
result.push({name: "No results"});
}
cb(result);
}
}]);
@@ -55,9 +53,9 @@ async function initLabelValueAutocomplete({ $el, open }) {
$el.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {

View File

@@ -3,14 +3,13 @@ import utils from "./utils.js";
import messagingService from "./messaging.js";
import treeUtils from "./tree_utils.js";
import noteAutocompleteService from "./note_autocomplete.js";
import treeService from "./tree.js";
import linkService from "./link.js";
import infoService from "./info.js";
import noteDetailService from "./note_detail.js";
const $attributeList = $("#attribute-list");
const $attributeListInner = $("#attribute-list-inner");
const $promotedAttributesContainer = $("#note-detail-promoted-attributes");
const $savedIndicator = $("#saved-indicator");
let attributePromise;
@@ -146,7 +145,8 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {
@@ -161,6 +161,14 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
}
else if (definition.labelType === 'number') {
$input.prop("type", "number");
let step = 1;
for (let i = 0; i < (definition.numberPrecision || 0) && i < 10; i++) {
step /= 10;
}
$input.prop("step", step);
}
else if (definition.labelType === 'boolean') {
$input.prop("type", "checkbox");
@@ -267,7 +275,12 @@ async function promotedAttributeChanged(event) {
$attr.prop("attribute-id", result.attributeId);
infoService.showMessage("Attribute has been saved.");
// animate only if it's not being animated already, this is important especially for e.g. number inputs
// which can be changed many times in a second by clicking on higher/lower buttons.
if ($savedIndicator.queue().length === 0) {
$savedIndicator.fadeOut();
$savedIndicator.fadeIn();
}
}
export default {

View File

@@ -7,6 +7,7 @@ import recentChangesDialog from '../dialogs/recent_changes.js';
import optionsDialog from '../dialogs/options.js';
import sqlConsoleDialog from '../dialogs/sql_console.js';
import markdownImportDialog from '../dialogs/markdown_import.js';
import exportDialog from '../dialogs/export.js';
import cloning from './cloning.js';
import contextMenu from './tree_context_menu.js';
@@ -103,12 +104,12 @@ if (utils.isElectron()) {
});
}
$("#export-note-to-markdown-button").click(function () {
$("#export-note-button").click(function () {
if ($(this).hasClass("disabled")) {
return;
}
exportService.exportSubtree(noteDetailService.getCurrentNoteId(), 'markdown-single')
exportDialog.showDialog('single');
});
treeService.showTree();

View File

@@ -43,8 +43,8 @@ function registerEntrypoints() {
$("#recent-changes-button").click(recentChangesDialog.showDialog);
$("#protected-session-on").click(protectedSessionService.enterProtectedSession);
$("#protected-session-off").click(protectedSessionService.leaveProtectedSession);
$("#enter-protected-session-button").click(protectedSessionService.enterProtectedSession);
$("#leave-protected-session-button").click(protectedSessionService.leaveProtectedSession);
$("#toggle-search-button").click(searchNotesService.toggleSearch);
utils.bindShortcut('ctrl+s', searchNotesService.toggleSearch);
@@ -97,10 +97,17 @@ function registerEntrypoints() {
$(document).bind('keydown', 'ctrl+f', () => {
if (utils.isElectron()) {
const searchInPage = require('electron-in-page-search').default;
const remote = require('electron').remote;
const $searchWindowWebview = $(".electron-in-page-search-window");
$searchWindowWebview.show();
const inPageSearch = searchInPage(remote.getCurrentWebContents());
const searchInPage = require('electron-in-page-search').default;
const {remote} = require('electron');
const inPageSearch = searchInPage(remote.getCurrentWebContents(), {
searchWindowWebview: $searchWindowWebview[0],
//openDevToolsOfSearchWindow: true,
customCssPath: '/libraries/electron-in-page-search/default-style.css'
});
inPageSearch.openSearchWindow();

View File

@@ -1,16 +1,14 @@
import treeService from './tree.js';
import infoService from './info.js';
import protectedSessionHolder from './protected_session_holder.js';
import utils from './utils.js';
import server from './server.js';
function exportSubtree(noteId, format) {
const url = utils.getHost() + "/api/notes/" + noteId + "/export/" + format +
"?protectedSessionId=" + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
function exportBranch(branchId, type, format) {
const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}?protectedSessionId=` + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
console.log(url);
utils.download(url);
infoService.showMessage("Export to file has been finished.");
}
let importNoteId;
@@ -47,6 +45,6 @@ $("#import-upload").change(async function() {
});
export default {
exportSubtree,
exportBranch,
importIntoNote
};

View File

@@ -5,13 +5,9 @@ function showMessage(message) {
console.debug(utils.now(), "message: ", message);
$.notify({
// options
icon: 'jam jam-check',
message: message
}, {
// options
type: 'success',
delay: 3000
});
}, getNotifySettings('success', 3000));
}
function showAndLogError(message, delay = 10000) {
@@ -25,12 +21,26 @@ function showError(message, delay = 10000) {
$.notify({
// options
icon: 'jam jam-alert',
message: message
}, {
// options
type: 'danger',
}, getNotifySettings('danger', delay));
}
function getNotifySettings(type, delay) {
return {
element: 'body',
type: type,
z_index: 90000,
placement: {
from: "top",
align: "center"
},
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
delay: delay
});
};
}
function throwError(message) {

View File

@@ -76,7 +76,8 @@ function initNoteAutocomplete($el, options) {
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [
{
source: autocompleteSource,
@@ -92,7 +93,7 @@ function initNoteAutocomplete($el, options) {
$el.on('autocomplete:selected', (event, suggestion) => $el.setSelectedPath(suggestion.path));
$el.on('autocomplete:closed', () => {
if (!$el.val().trim()) {
$el.setSelectedPath("");
clearText($el);
}
});
}

View File

@@ -28,6 +28,7 @@ const $noteDetailWrapper = $("#note-detail-wrapper");
const $noteIdDisplay = $("#note-id-display");
const $childrenOverview = $("#children-overview");
const $scriptArea = $("#note-detail-script-area");
const $savedIndicator = $("#saved-indicator");
let currentNote = null;
@@ -78,6 +79,8 @@ function noteChanged() {
}
isNoteChanged = true;
$savedIndicator.fadeOut();
}
async function reload() {
@@ -120,15 +123,16 @@ async function saveNote() {
protectedSessionHolder.touchProtectedSession();
}
infoService.showMessage("Saved!");
$savedIndicator.fadeIn();
}
async function saveNoteIfChanged() {
if (!isNoteChanged) {
return;
if (isNoteChanged) {
await saveNote();
}
await saveNote();
// make sure indicator is visible in a case there was some race condition.
$savedIndicator.fadeIn();
}
function setNoteBackgroundIfProtected(note) {
@@ -294,7 +298,7 @@ $(document).ready(() => {
// this sends the request asynchronously and doesn't wait for result
$(window).on('beforeunload', () => { saveNoteIfChanged(); }); // don't convert to short form, handler doesn't like returned promise
setInterval(saveNoteIfChanged, 5000);
setInterval(saveNoteIfChanged, 3000);
export default {
reload,

View File

@@ -32,7 +32,10 @@ async function show() {
lint: true,
gutters: ["CodeMirror-lint-markers"],
lineNumbers: true,
tabindex: 100
tabindex: 100,
// we linewrap partly also because without it horizontal scrollbar displays only when you scroll
// all the way to the bottom of the note. With line wrap there's no horizontal scrollbar so no problem
lineWrapping: true
});
onNoteChange(noteDetailService.noteChanged);
@@ -43,7 +46,9 @@ async function show() {
const currentNote = noteDetailService.getCurrentNote();
// this needs to happen after the element is shown, otherwise the editor won't be refreshed
codeEditor.setValue(currentNote.content);
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
// we provide fallback
codeEditor.setValue(currentNote.content || "");
const info = CodeMirror.findModeByMIME(currentNote.mime);

View File

@@ -11,8 +11,8 @@ const $password = $("#protected-session-password");
const $noteDetailWrapper = $("#note-detail-wrapper");
const $protectButton = $("#protect-button");
const $unprotectButton = $("#unprotect-button");
const $protectedSessionOnButton = $("#protected-session-on");
const $protectedSessionOffButton = $("#protected-session-off");
const $enterProtectedSessionButton = $("#enter-protected-session-button");
const $leaveProtectedSessionButton = $("#leave-protected-session-button");
let protectedSessionDeferred = null;
@@ -57,7 +57,7 @@ async function setupProtectedSession() {
const response = await enterProtectedSessionOnServer(password);
if (!response.success) {
infoService.showError("Wrong password.");
infoService.showError("Wrong password.", 3000);
return;
}
@@ -65,9 +65,11 @@ async function setupProtectedSession() {
$dialog.modal("hide");
await noteDetailService.reload();
await treeService.reload();
treeService.reload();
// it's important that tree has been already reloaded at this point
// since detail also uses tree cache (for children overview)
await noteDetailService.reload();
if (protectedSessionDeferred !== null) {
ensureDialogIsClosed($dialog, $password);
@@ -77,8 +79,8 @@ async function setupProtectedSession() {
protectedSessionDeferred.resolve(true);
protectedSessionDeferred = null;
$protectedSessionOnButton.addClass('active');
$protectedSessionOffButton.removeClass('active');
$enterProtectedSessionButton.hide();
$leaveProtectedSessionButton.show();
}
infoService.showMessage("Protected session has been started.");

View File

@@ -12,9 +12,10 @@ function getHeaders() {
// headers need to be lowercase because node.js automatically converts them to lower case
// so hypothetical protectedSessionId becomes protectedsessionid on the backend
// also avoiding using underscores instead of dashes since nginx filters them out by default
return {
protected_session_id: protectedSessionId,
source_id: glob.sourceId
'trilium-protected-session-id': protectedSessionId,
'trilium-source-id': glob.sourceId
};
}

View File

@@ -44,7 +44,7 @@ function setupTooltip() {
container: 'body',
placement: 'auto',
trigger: 'manual',
boundariesElement: 'window',
boundary: 'window',
title: html,
html: true
});

View File

@@ -500,6 +500,12 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
if (noteDetailService.getCurrentNoteType() !== 'text') {
saveSelection = false;
}
else {
// just disable this feature altogether - there's a problem that note containing image or table at the beginning
// of the content will be auto-selected by CKEditor and then CTRL-P with no user interaction will automatically save
// the selection - see https://github.com/ckeditor/ckeditor5/issues/1384
saveSelection = false;
}
let title, content;
@@ -564,8 +570,6 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
clearSelectedNodes(); // to unmark previously active node
infoService.showMessage("Created!");
return {note, branch};
}

View File

@@ -6,7 +6,7 @@ import protectedSessionService from './protected_session.js';
import treeChangesService from './branches.js';
import treeUtils from './tree_utils.js';
import branchPrefixDialog from '../dialogs/branch_prefix.js';
import exportSubtreeDialog from '../dialogs/export_subtree.js';
import exportDialog from '../dialogs/export.js';
import infoService from "./info.js";
import treeCache from "./tree_cache.js";
import syncService from "./sync.js";
@@ -93,7 +93,7 @@ const contextMenuItems = [
{title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "clipboard"},
{title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard"},
{title: "----"},
{title: "Export subtree", cmd: "exportSubtree", uiIcon: "arrow-up-right"},
{title: "Export", cmd: "export", uiIcon: "arrow-up-right"},
{title: "Import into note (tar, opml, md, enex)", cmd: "importIntoNote", uiIcon: "arrow-down-left"},
{title: "----"},
{title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify"},
@@ -127,7 +127,7 @@ async function getContextMenuItems(event) {
enableItem("pasteAfter", clipboardIds.length > 0 && isNotRoot && parentNote.type !== 'search');
enableItem("pasteInto", clipboardIds.length > 0 && note.type !== 'search');
enableItem("importIntoNote", note.type !== 'search');
enableItem("exportSubtree", note.type !== 'search');
enableItem("export", note.type !== 'search');
enableItem("editBranchPrefix", isNotRoot && parentNote.type !== 'search');
// Activate node on right-click
@@ -179,8 +179,8 @@ function selectContextMenuItem(event, cmd) {
else if (cmd === "delete") {
treeChangesService.deleteNodes(treeService.getSelectedNodes(true));
}
else if (cmd === "exportSubtree") {
exportSubtreeDialog.showDialog();
else if (cmd === "export") {
exportDialog.showDialog("subtree");
}
else if (cmd === "importIntoNote") {
exportService.importIntoNote(node.data.noteId);

View File

@@ -0,0 +1,57 @@
html, body {
margin: 0;
width: 100%;
height: 100%;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Meiryo", sans-serif;
overflow: hidden;
}
.inpage-search-body {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin: 8px;
padding: 10px;
border: solid #aaaaaa 1px;
border-radius: 10px;
background-color: #fafafa;
}
.inpage-search-input {
width: 200px;
}
.inpage-search-matches {
color: #999;
font-size: 0.8em;
}
.inpage-search-back {
margin-left: 2px;
padding-left: 6px;
padding-right: 2px;
cursor: pointer;
}
.inpage-search-forward {
padding-left: 2px;
padding-right: 6px;
cursor: pointer;
}
.inpage-search-close {
margin-left: 4px;
padding: 0 2px;
cursor: pointer;
}
.inpage-search-back:hover,
.inpage-search-forward:hover,
.inpage-search-close:hover {
background-color: #e2e0e2;
border-radius: 0.2em;
}

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes" />
<link href="/libraries/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="inpage-search-body">
<input class="inpage-search-input form-control form-control-sm" type="search" placeholder="Search..." autocomplete="off" autofocus/>
<div class="inpage-search-matches">0/0</div>
<div class="inpage-search-back" title="Previous result">&lt;</div>
<div class="inpage-search-forward" title="Next result">&gt;</div>
<div class="inpage-search-close" title="Close search"></div>
</div>
</body>
<script>var exports = {}</script>
</html>

View File

@@ -77,9 +77,12 @@ body {
overflow: auto;
flex-basis: content;
height: 100%;
display: flex;
flex-direction: column;
}
.note-detail-component {
flex-grow: 100;
display: none;
}
@@ -211,12 +214,12 @@ div.ui-tooltip {
*/
.electron-in-page-search-window {
position: fixed;
top: 50px;
right: 0;
border: solid grey 1px;
background-color: white;
width: 300px;
height: 36px;
top: 45px;
right: 10px;
width: 360px;
height: 55px;
display: none;
z-index: 1001;
}
/*
@@ -344,11 +347,11 @@ div.ui-tooltip {
#children-overview {
flex-grow: 1000;
flex-shrink: 1000;
flex-basis: 0px;
flex-basis: 0;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
height: 100px;
height: 110px;
overflow: auto;
}
@@ -528,12 +531,12 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
padding: 20px;
}
.context-menu {
.context-menu-container {
font-size: small;
}
.context-menu .dropdown-item {
padding: 2px 10px 2px 10px;
#context-menu-container .dropdown-item {
padding: 0 7px 0 10px;
}
/* if modal height overflows, then only modal body scrolls */
@@ -542,6 +545,11 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
overflow-y: auto;
}
/* this should help with tooltip flickering */
.tooltip {
pointer-events: none;
}
.tooltip-inner {
background-color: #fbfbfb !important;
max-width: 400px;
@@ -612,11 +620,11 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
}
.modalless {
top:10%;
left:50%;
bottom:auto;
right:auto;
margin-left:-300px;
top: 15%;
left: 40%;
bottom: auto;
right: auto;
margin-left: -300px;
}
.multiplicity {
@@ -626,4 +634,68 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
/* this is because bootstrap (?) sets code color to red for some reason */
code {
color: inherit !important;
}
.animated {
animation-duration: 1s;
animation-fill-mode: both;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInDown {
animation-name: fadeInDown;
}
@keyframes fadeOutUp {
from {
opacity: 1;
}
to {
opacity: 0;
-webkit-transform: translate3d(0, -100%, 0);
transform: translate3d(0, -100%, 0);
}
}
.fadeOutUp {
animation-name: fadeOutUp;
}
div[data-notify="container"] {
text-align: center;
}
#saved-indicator {
position: absolute;
right: 10px;
top: 11px;
font-size: x-large;
color: #777;
z-index: 100;
}
#export-form .form-check {
padding-top: 10px;
padding-bottom: 10px;
}
#export-form .format-choice {
padding-left: 40px;
display: none;
}
#export-form .form-check-label {
padding: 2px;
}

View File

@@ -1,28 +1,22 @@
"use strict";
const nativeTarExportService = require('../../services/export/native_tar');
const markdownTarExportService = require('../../services/export/markdown_tar');
const markdownSingleExportService = require('../../services/export/markdown_single');
const tarExportService = require('../../services/export/tar');
const singleExportService = require('../../services/export/single');
const opmlExportService = require('../../services/export/opml');
const repository = require("../../services/repository");
async function exportNote(req, res) {
// entityId maybe either noteId or branchId depending on format
const entityId = req.params.entityId;
const format = req.params.format;
async function exportBranch(req, res) {
const {branchId, type, format} = req.params;
const branch = await repository.getBranch(branchId);
if (format === 'native-tar') {
await nativeTarExportService.exportToTar(await repository.getBranch(entityId), res);
if (type === 'subtree' && (format === 'html' || format === 'markdown')) {
await tarExportService.exportToTar(branch, format, res);
}
else if (format === 'markdown-tar') {
await markdownTarExportService.exportToMarkdown(await repository.getBranch(entityId), res);
}
// export single note without subtree
else if (format === 'markdown-single') {
await markdownSingleExportService.exportSingleMarkdown(await repository.getNote(entityId), res);
else if (type === 'single') {
await singleExportService.exportSingleNote(branch, format, res);
}
else if (format === 'opml') {
await opmlExportService.exportToOpml(await repository.getBranch(entityId), res);
await opmlExportService.exportToOpml(branch, res);
}
else {
return [404, "Unrecognized export format " + format];
@@ -30,5 +24,5 @@ async function exportNote(req, res) {
}
module.exports = {
exportNote
exportBranch
};

View File

@@ -4,7 +4,8 @@ const repository = require('../../services/repository');
const enexImportService = require('../../services/import/enex');
const opmlImportService = require('../../services/import/opml');
const tarImportService = require('../../services/import/tar');
const markdownImportService = require('../../services/import/markdown');
const singleImportService = require('../../services/import/single');
const cls = require('../../services/cls');
const path = require('path');
async function importToBranch(req) {
@@ -23,6 +24,10 @@ async function importToBranch(req) {
const extension = path.extname(file.originalname).toLowerCase();
// running all the event handlers on imported notes (and attributes) is slow
// and may produce unintended consequences
cls.disableEntityEvents();
if (extension === '.tar') {
return await tarImportService.importTar(file.buffer, parentNote);
}
@@ -30,7 +35,10 @@ async function importToBranch(req) {
return await opmlImportService.importOpml(file.buffer, parentNote);
}
else if (extension === '.md') {
return await markdownImportService.importMarkdown(file, parentNote);
return await singleImportService.importMarkdown(file, parentNote);
}
else if (extension === '.html' || extension === '.htm') {
return await singleImportService.importHtml(file, parentNote);
}
else if (extension === '.enex') {
return await enexImportService.importEnex(file, parentNote);

View File

@@ -66,7 +66,7 @@ function route(method, path, middleware, routeHandler, resultHandler, transactio
router[method](path, ...middleware, async (req, res, next) => {
try {
const result = await cls.init(async () => {
cls.namespace.set('sourceId', req.headers.source_id);
cls.namespace.set('sourceId', req.headers['trilium-source-id']);
protectedSessionService.setProtectedSessionId(req);
if (transactional) {
@@ -128,7 +128,7 @@ function register(app) {
apiRoute(PUT, '/api/notes/:noteId/clone-to/:parentNoteId', cloningApiRoute.cloneNoteToParent);
apiRoute(PUT, '/api/notes/:noteId/clone-after/:afterBranchId', cloningApiRoute.cloneNoteAfter);
route(GET, '/api/notes/:entityId/export/:format', [auth.checkApiAuthOrElectron], exportRoute.exportNote);
route(GET, '/api/notes/:branchId/export/:type/:format', [auth.checkApiAuthOrElectron], exportRoute.exportBranch);
route(POST, '/api/notes/:parentNoteId/import', [auth.checkApiAuthOrElectron, uploadMiddleware], importRoute.importToBranch, apiResultHandler);
route(POST, '/api/notes/:parentNoteId/upload', [auth.checkApiAuthOrElectron, uploadMiddleware],

67
src/services/app_icon.js Normal file
View File

@@ -0,0 +1,67 @@
"use strict";
const path = require('path');
const {APP_PNG_ICON_DIR, ELECTRON_APP_ROOT_DIR} = require("./resource_dir");
const log = require("./log");
const os = require('os');
const fs = require('fs');
const config = require('./config');
const utils = require('./utils');
const template = `[Desktop Entry]
Type=Application
Name=Trilium Notes
Icon=#APP_PNG_ICON_DIR#/128x128.png
Exec=#EXE_PATH#
Categories=Office
Terminal=false
`;
/**
* Installs .desktop icon into standard ~/.local/share/applications directory.
* We overwrite this file during every run as it might have been updated.
*/
function installLocalAppIcon() {
if (!utils.isElectron()
|| ["win32", "darwin"].includes(os.platform())
|| (config.General && config.General.noDesktopIcon)) {
return;
}
const desktopDir = path.resolve(os.homedir(), '.local/share/applications');
fs.stat(desktopDir, function (err, stats) {
if (err) {
// Directory doesn't exist so we won't attempt to create the .desktop file
return;
}
if (stats.isDirectory()) {
const desktopFilePath = path.resolve(desktopDir, "trilium-notes.desktop");
fs.writeFile(desktopFilePath, getDesktopFileContent(), function (err) {
if (err) {
log.error("Desktop icon installation to ~/.local/share/applications failed.");
}
});
}
});
}
function getDesktopFileContent() {
return template
.replace("#APP_PNG_ICON_DIR#", escapePath(APP_PNG_ICON_DIR))
.replace("#EXE_PATH#", escapePath(getExePath()));
}
function escapePath(path) {
return path.replace(" ", "\\ ");
}
function getExePath() {
return path.resolve(ELECTRON_APP_ROOT_DIR, 'trilium');
}
module.exports = {
installLocalAppIcon
};

View File

@@ -3,7 +3,7 @@
const build = require('./build');
const packageJson = require('../../package');
const APP_DB_VERSION = 119;
const APP_DB_VERSION = 120;
const SYNC_VERSION = 2;
module.exports = {

View File

@@ -225,6 +225,8 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
*/
this.transactional = sql.transactional;
this.sql = sql;
/**
* Trigger tree refresh in all connected clients. This is required when some tree change happens in
* the backend.

View File

@@ -1 +1 @@
module.exports = { buildDate:"2018-11-19T17:17:08+01:00", buildRevision: "3fd45b15e7042c12f140524297b50677f9851044" };
module.exports = { buildDate:"2018-12-02T00:30:07+01:00", buildRevision: "350cb52c07668f67c4d9c7700ceb9f91445a1acb" };

View File

@@ -13,6 +13,14 @@ function getSourceId() {
return namespace.get('sourceId');
}
function disableEntityEvents() {
namespace.set('disableEntityEvents', true);
}
function isEntityEventsDisabled() {
return !!namespace.get('disableEntityEvents');
}
function reset() {
clsHooked.reset();
}
@@ -22,5 +30,7 @@ module.exports = {
wrap,
namespace,
getSourceId,
disableEntityEvents,
isEntityEventsDisabled,
reset
};

View File

@@ -209,6 +209,16 @@ async function runAllChecks() {
AND type != 'relation-map'`,
"Note has invalid type", errorList);
await runCheck(`
SELECT
noteId
FROM
notes
WHERE
isDeleted = 0
AND content IS NULL`,
"Note content is null even though it is not deleted", errorList);
await runCheck(`
SELECT
parentNoteId

View File

@@ -1,14 +1,64 @@
"use strict";
/*
* This file resolves trilium data path in this order of priority:
* - if TRILIUM_DATA_DIR environment variable exists, then its value is used as the path
* - if "trilium-data" dir exists directly in the home dir, then it is used
* - based on OS convention, if the "app data directory" exists, we'll use or create "trilium-data" directory there
* - as a fallback if previous step fails, we'll use home dir
*/
const os = require('os');
const fs = require('fs');
const TRILIUM_DATA_DIR = process.env.TRILIUM_DATA_DIR || os.homedir() + "/trilium-data";
function getAppDataDir() {
let appDataDir = os.homedir(); // fallback if OS is not recognized
if (!fs.existsSync(TRILIUM_DATA_DIR)) {
fs.mkdirSync(TRILIUM_DATA_DIR, 0o700);
if (os.platform() === 'win32') {
appDataDir = process.env.APPDATA;
}
else if (os.platform() === 'linux') {
appDataDir = os.homedir() + '/.local/share';
}
else if (os.platform() === 'darwin') {
appDataDir = os.homedir() + '/Library/Application Support';
}
if (!fs.existsSync(appDataDir)) {
// expected app data path doesn't exist, let's use fallback
appDataDir = os.homedir();
}
return appDataDir;
}
const DIR_NAME = 'trilium-data';
function getTriliumDataDir() {
if (process.env.TRILIUM_DATA_DIR) {
return process.env.TRILIUM_DATA_DIR;
}
const homePath = os.homedir() + "/" + DIR_NAME;
if (fs.existsSync(homePath)) {
return homePath;
}
const appDataPath = getAppDataDir() + '/' + DIR_NAME;
if (!fs.existsSync(appDataPath)) {
fs.mkdirSync(appDataPath, 0o700);
}
return appDataPath;
}
const TRILIUM_DATA_DIR = getTriliumDataDir();
// not necessary to log this since if we have logs we already know where data dir is.
console.log("Using data dir:", TRILIUM_DATA_DIR);
const DOCUMENT_PATH = TRILIUM_DATA_DIR + "/document.db";
const BACKUP_DIR = TRILIUM_DATA_DIR + "/backup";
const LOG_DIR = TRILIUM_DATA_DIR + "/log";

View File

@@ -1,31 +0,0 @@
"use strict";
const sanitize = require("sanitize-filename");
const TurndownService = require('turndown');
async function exportSingleMarkdown(note, res) {
if (note.type !== 'text' && note.type !== 'code') {
return [400, `Note type ${note.type} cannot be exported as single markdown file.`];
}
let markdown;
if (note.type === 'code') {
markdown = '```\n' + note.content + "\n```";
}
else if (note.type === 'text') {
const turndownService = new TurndownService();
markdown = turndownService.turndown(note.content);
}
const name = sanitize(note.title);
res.setHeader('Content-Disposition', 'file; filename="' + name + '.md"');
res.setHeader('Content-Type', 'text/markdown; charset=UTF-8');
res.send(markdown);
}
module.exports = {
exportSingleMarkdown
};

View File

@@ -1,91 +0,0 @@
"use strict";
const tar = require('tar-stream');
const TurndownService = require('turndown');
const sanitize = require("sanitize-filename");
const markdownSingleExportService = require('../../services/export/markdown_single');
async function exportToMarkdown(branch, res) {
const note = await branch.getNote();
if (!await note.hasChildren()) {
await markdownSingleExportService.exportSingleMarkdown(note, res);
return;
}
const turndownService = new TurndownService();
const pack = tar.pack();
const name = await exportNoteInner(note, '');
async function exportNoteInner(note, directory) {
const childFileName = directory + sanitize(note.title);
if (await note.hasLabel('excludeFromExport')) {
return;
}
saveNote(childFileName, note);
const childNotes = await note.getChildNotes();
if (childNotes.length > 0) {
saveDirectory(childFileName);
}
for (const childNote of childNotes) {
await exportNoteInner(childNote, childFileName + "/");
}
return childFileName;
}
function saveTextNote(childFileName, note) {
if (note.content.trim().length === 0) {
return;
}
let markdown;
if (note.type === 'code') {
markdown = '```\n' + note.content + "\n```";
}
else if (note.type === 'text') {
markdown = turndownService.turndown(note.content);
}
else {
// other note types are not supported
return;
}
pack.entry({name: childFileName + ".md", size: markdown.length}, markdown);
}
function saveFileNote(childFileName, note) {
pack.entry({name: childFileName, size: note.content.length}, note.content);
}
function saveNote(childFileName, note) {
if (note.type === 'text' || note.type === 'code') {
saveTextNote(childFileName, note);
}
else if (note.type === 'image' || note.type === 'file') {
saveFileNote(childFileName, note);
}
}
function saveDirectory(childFileName) {
pack.entry({name: childFileName, type: 'directory'});
}
pack.finalize();
res.setHeader('Content-Disposition', 'file; filename="' + name + '.tar"');
res.setHeader('Content-Type', 'application/tar');
pack.pipe(res);
}
module.exports = {
exportToMarkdown
};

View File

@@ -1,103 +0,0 @@
"use strict";
const html = require('html');
const native_tar = require('tar-stream');
const sanitize = require("sanitize-filename");
async function exportToTar(branch, res) {
const pack = native_tar.pack();
const exportedNoteIds = [];
const name = await exportNoteInner(branch, '');
async function exportNoteInner(branch, directory) {
const note = await branch.getNote();
const childFileName = directory + sanitize(note.title);
if (exportedNoteIds.includes(note.noteId)) {
saveMetadataFile(childFileName, {
version: 1,
clone: true,
noteId: note.noteId,
prefix: branch.prefix
});
return;
}
const metadata = {
version: 1,
clone: false,
noteId: note.noteId,
title: note.title,
prefix: branch.prefix,
isExpanded: branch.isExpanded,
type: note.type,
mime: note.mime,
// we don't export dateCreated and dateModified of any entity since that would be a bit misleading
attributes: (await note.getOwnedAttributes()).map(attribute => {
return {
type: attribute.type,
name: attribute.name,
value: attribute.value,
isInheritable: attribute.isInheritable,
position: attribute.position
};
}),
links: (await note.getLinks()).map(link => {
return {
type: link.type,
targetNoteId: link.targetNoteId
}
})
};
if (await note.hasLabel('excludeFromExport')) {
return;
}
saveMetadataFile(childFileName, metadata);
saveDataFile(childFileName, note);
exportedNoteIds.push(note.noteId);
const childBranches = await note.getChildBranches();
if (childBranches.length > 0) {
saveDirectory(childFileName);
}
for (const childBranch of childBranches) {
await exportNoteInner(childBranch, childFileName + "/");
}
return childFileName;
}
function saveDataFile(childFileName, note) {
const content = note.type === 'text' ? html.prettyPrint(note.content, {indent_size: 2}) : note.content;
pack.entry({name: childFileName + ".dat", size: content.length}, content);
}
function saveMetadataFile(childFileName, metadata) {
const metadataJson = JSON.stringify(metadata, null, '\t');
pack.entry({name: childFileName + ".meta", size: metadataJson.length}, metadataJson);
}
function saveDirectory(childFileName) {
pack.entry({name: childFileName, type: 'directory'});
}
pack.finalize();
res.setHeader('Content-Disposition', 'file; filename="' + name + '.tar"');
res.setHeader('Content-Type', 'application/tar');
pack.pipe(res);
}
module.exports = {
exportToTar
};

View File

@@ -0,0 +1,57 @@
"use strict";
const sanitize = require("sanitize-filename");
const TurndownService = require('turndown');
const mimeTypes = require('mime-types');
const html = require('html');
async function exportSingleNote(branch, format, res) {
const note = await branch.getNote();
if (note.type === 'image' || note.type === 'file') {
return [400, `Note type ${note.type} cannot be exported as single file.`];
}
if (format !== 'html' && format !== 'markdown') {
return [400, 'Unrecognized format ' + format];
}
let payload, extension, mime;
if (note.type === 'text') {
if (format === 'html') {
payload = html.prettyPrint(note.content, {indent_size: 2});
extension = 'html';
mime = 'text/html';
}
else if (format === 'markdown') {
const turndownService = new TurndownService();
payload = turndownService.turndown(note.content);
extension = 'md';
mime = 'text/markdown'
}
}
else if (note.type === 'code') {
payload = note.content;
extension = mimeTypes.extension(note.mime) || 'code';
mime = note.mime;
}
else if (note.type === 'relation-map' || note.type === 'search') {
payload = note.content;
extension = 'json';
mime = 'application/json';
}
const name = sanitize(note.title);
console.log(name, extension, mime);
res.setHeader('Content-Disposition', `file; filename="${name}.${extension}"`);
res.setHeader('Content-Type', mime + '; charset=UTF-8');
res.send(payload);
}
module.exports = {
exportSingleNote
};

232
src/services/export/tar.js Normal file
View File

@@ -0,0 +1,232 @@
"use strict";
const html = require('html');
const repository = require('../repository');
const tar = require('tar-stream');
const path = require('path');
const sanitize = require("sanitize-filename");
const mimeTypes = require('mime-types');
const TurndownService = require('turndown');
const packageInfo = require('../../../package.json');
/**
* @param format - 'html' or 'markdown'
*/
async function exportToTar(branch, format, res) {
let turndownService = format === 'markdown' ? new TurndownService() : null;
const pack = tar.pack();
const noteIdToMeta = {};
function getUniqueFilename(existingFileNames, fileName) {
const lcFileName = fileName.toLowerCase();
if (lcFileName in existingFileNames) {
let index;
let newName;
do {
index = existingFileNames[lcFileName]++;
newName = lcFileName + "_" + index;
}
while (newName in existingFileNames);
return fileName + "_" + index;
}
else {
existingFileNames[lcFileName] = 1;
return fileName;
}
}
function getDataFileName(note, baseFileName, existingFileNames) {
let extension;
if (note.type === 'text' && format === 'markdown') {
extension = 'md';
}
else if (note.mime === 'application/x-javascript' || note.mime === 'text/javascript') {
extension = 'js';
}
else {
extension = mimeTypes.extension(note.mime) || "dat";
}
let fileName = baseFileName;
const existingExtension = path.extname(fileName).toLowerCase();
// if the note is already named with extension (e.g. "jquery.js"), then it's silly to append exact same extension again
if (existingExtension !== extension) {
fileName += "." + extension;
}
return getUniqueFilename(existingFileNames, fileName);
}
async function getNote(branch, existingFileNames) {
const note = await branch.getNote();
if (await note.hasLabel('excludeFromExport')) {
return;
}
const baseFileName = branch.prefix ? (branch.prefix + ' - ' + note.title) : note.title;
if (note.noteId in noteIdToMeta) {
const sanitizedFileName = sanitize(baseFileName + ".clone");
const fileName = getUniqueFilename(existingFileNames, sanitizedFileName);
return {
isClone: true,
noteId: note.noteId,
prefix: branch.prefix,
dataFileName: fileName
};
}
const meta = {
isClone: false,
noteId: note.noteId,
title: note.title,
notePosition: branch.notePosition,
prefix: branch.prefix,
isExpanded: branch.isExpanded,
type: note.type,
mime: note.mime,
// we don't export dateCreated and dateModified of any entity since that would be a bit misleading
attributes: (await note.getOwnedAttributes()).map(attribute => {
return {
type: attribute.type,
name: attribute.name,
value: attribute.value,
isInheritable: attribute.isInheritable,
position: attribute.position
};
}),
links: (await note.getLinks()).map(link => {
return {
type: link.type,
targetNoteId: link.targetNoteId
}
})
};
if (note.type === 'text') {
meta.format = format;
}
noteIdToMeta[note.noteId] = meta;
const childBranches = await note.getChildBranches();
// if it's a leaf then we'll export it even if it's empty
if (note.content.length > 0 || childBranches.length === 0) {
meta.dataFileName = getDataFileName(note, baseFileName, existingFileNames);
}
if (childBranches.length > 0) {
meta.dirFileName = getUniqueFilename(existingFileNames, baseFileName);
meta.children = [];
// namespace is shared by children in the same note
const childExistingNames = {};
for (const childBranch of childBranches) {
const note = await getNote(childBranch, childExistingNames);
// can be undefined if export is disabled for this note
if (note) {
meta.children.push(note);
}
}
}
return meta;
}
function prepareContent(note, format) {
if (format === 'html') {
return html.prettyPrint(note.content, {indent_size: 2});
}
else if (format === 'markdown') {
return turndownService.turndown(note.content);
}
else {
return note.content;
}
}
// noteId => file path
const notePaths = {};
async function saveNote(noteMeta, path) {
if (noteMeta.isClone) {
const content = "Note is present at " + notePaths[noteMeta.noteId];
pack.entry({name: path + noteMeta.dataFileName, size: content.length}, content);
return;
}
const note = await repository.getNote(noteMeta.noteId);
notePaths[note.noteId] = path + (noteMeta.dataFileName || noteMeta.dirFileName);
if (noteMeta.dataFileName) {
const content = prepareContent(note, noteMeta.format);
pack.entry({name: path + noteMeta.dataFileName, size: content.length}, content);
}
if (noteMeta.children && noteMeta.children.length > 0) {
const directoryPath = path + noteMeta.dirFileName;
pack.entry({name: directoryPath, type: 'directory'});
for (const childMeta of noteMeta.children) {
await saveNote(childMeta, directoryPath + '/');
}
}
}
const metaFile = {
formatVersion: 1,
appVersion: packageInfo.version,
files: [
await getNote(branch, [])
]
};
for (const noteMeta of Object.values(noteIdToMeta)) {
// filter out relations and links which are not inside this export
noteMeta.attributes = noteMeta.attributes.filter(attr => attr.type !== 'relation' || attr.value in noteIdToMeta);
noteMeta.links = noteMeta.links.filter(link => link.targetNoteId in noteIdToMeta);
}
if (!metaFile.files[0]) { // corner case of disabled export for exported note
res.sendStatus(400);
return;
}
const metaFileJson = JSON.stringify(metaFile, null, '\t');
pack.entry({name: "!!!meta.json", size: metaFileJson.length}, metaFileJson);
await saveNote(metaFile.files[0], '');
pack.finalize();
const note = await branch.getNote();
const tarFileName = sanitize((branch.prefix ? (branch.prefix + " - ") : "") + note.title);
res.setHeader('Content-Disposition', `file; filename="${tarFileName}.tar"`);
res.setHeader('Content-Type', 'application/tar');
pack.pipe(res);
}
module.exports = {
exportToTar
};

View File

@@ -1,30 +0,0 @@
"use strict";
// note that this is for import of single markdown file only - for archive/structure of markdown files
// see tar export/import
const noteService = require('../../services/notes');
const commonmark = require('commonmark');
async function importMarkdown(file, parentNote) {
const markdownContent = file.buffer.toString("UTF-8");
const reader = new commonmark.Parser();
const writer = new commonmark.HtmlRenderer();
const parsed = reader.parse(markdownContent);
const htmlContent = writer.render(parsed);
const title = file.originalname.substr(0, file.originalname.length - 3); // strip .md extension
const {note} = await noteService.createNote(parentNote.noteId, title, htmlContent, {
type: 'text',
mime: 'text/html'
});
return note;
}
module.exports = {
importMarkdown
};

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