mirror of
https://github.com/zadam/trilium.git
synced 2025-10-26 15:56:29 +01:00
Compare commits
242 Commits
v0.24.4-be
...
v0.28.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a9a49b739 | ||
|
|
2ac560c56e | ||
|
|
c23387c0fb | ||
|
|
0ff250fe15 | ||
|
|
52b1e58b26 | ||
|
|
484715e440 | ||
|
|
9d42c3d802 | ||
|
|
c654172d33 | ||
|
|
e17b26c883 | ||
|
|
24d02d9cf5 | ||
|
|
7208a311ac | ||
|
|
ad7355372b | ||
|
|
f18b5babad | ||
|
|
9831ec0ca9 | ||
|
|
596544eca3 | ||
|
|
1f853024ee | ||
|
|
0308b13460 | ||
|
|
06b8a82f70 | ||
|
|
91ca07929d | ||
|
|
afabaa5fdb | ||
|
|
a6fd3fa77c | ||
|
|
58a2c08dcd | ||
|
|
299bbff2f4 | ||
|
|
19d8947123 | ||
|
|
35edce7523 | ||
|
|
bc4cec69a5 | ||
|
|
cce8c1b674 | ||
|
|
aa58788769 | ||
|
|
6c62ab7a52 | ||
|
|
d6ab638b30 | ||
|
|
bd4db406de | ||
|
|
e50f9cd0a3 | ||
|
|
2b64cbce2c | ||
|
|
2797c942ab | ||
|
|
f1c3278874 | ||
|
|
424c22dcde | ||
|
|
5c223dfd12 | ||
|
|
6a3e7a5a8e | ||
|
|
f88cdac000 | ||
|
|
eeead90f32 | ||
|
|
b607857409 | ||
|
|
9268f88bc3 | ||
|
|
f7f0560a9f | ||
|
|
3d8905207e | ||
|
|
dbc312010b | ||
|
|
b115a7cf19 | ||
|
|
348562352c | ||
|
|
70fd917e7c | ||
|
|
d2b60764cd | ||
|
|
581b1fdaa5 | ||
|
|
3c19a712c0 | ||
|
|
cc27f16088 | ||
|
|
dffdb82288 | ||
|
|
2b32addade | ||
|
|
0b251530fa | ||
|
|
f5b933149a | ||
|
|
48bbfb8bdb | ||
|
|
889971c4d6 | ||
|
|
0722494d41 | ||
|
|
4b977a3306 | ||
|
|
3ff3021acd | ||
|
|
99e56a9c42 | ||
|
|
77279dfe16 | ||
|
|
93f8050454 | ||
|
|
31cfede7a7 | ||
|
|
c8ec86e537 | ||
|
|
05aee884b6 | ||
|
|
012ba9e060 | ||
|
|
8e8fd88857 | ||
|
|
523ccdad6b | ||
|
|
ded3f605be | ||
|
|
62b44e3549 | ||
|
|
030d12a465 | ||
|
|
4d15628840 | ||
|
|
81b849898c | ||
|
|
3824486b85 | ||
|
|
081ab00a0a | ||
|
|
04f6af5c9a | ||
|
|
4dc1f1f6eb | ||
|
|
3930a02123 | ||
|
|
3112de105e | ||
|
|
3b8d7b8fba | ||
|
|
9fca7f09a5 | ||
|
|
fd39d6b3a9 | ||
|
|
a103886ea5 | ||
|
|
373408e401 | ||
|
|
db44c1d8e6 | ||
|
|
95a34c9e2d | ||
|
|
6ce401f260 | ||
|
|
5d74dcd256 | ||
|
|
5a9fc1697b | ||
|
|
927415838c | ||
|
|
d72fcefdc7 | ||
|
|
0be173a8f7 | ||
|
|
c3913a8735 | ||
|
|
e2dfe1b6de | ||
|
|
fec3e47eb8 | ||
|
|
d72efd2450 | ||
|
|
ef1c840aa7 | ||
|
|
1581464d8c | ||
|
|
9de29584a4 | ||
|
|
9e2e6fb50c | ||
|
|
c85979b66b | ||
|
|
ecdc5865a6 | ||
|
|
1771ddb787 | ||
|
|
3ab657fe46 | ||
|
|
8785dae753 | ||
|
|
2f1c5b29d4 | ||
|
|
7135349a10 | ||
|
|
66c639d5e3 | ||
|
|
6704b755d8 | ||
|
|
cf96baad48 | ||
|
|
32220476aa | ||
|
|
86bc84a2ad | ||
|
|
de9e0c7929 | ||
|
|
6963e662ef | ||
|
|
7127822e8f | ||
|
|
0a35abf68f | ||
|
|
3f8e8f8561 | ||
|
|
e02eca87b0 | ||
|
|
2f680c4326 | ||
|
|
0b4a44a403 | ||
|
|
89299f865c | ||
|
|
f6db9a50ab | ||
|
|
78d9fac1e6 | ||
|
|
458ed1faff | ||
|
|
0657815de5 | ||
|
|
a608832681 | ||
|
|
d2f72529b3 | ||
|
|
28185af158 | ||
|
|
7aacd01ad7 | ||
|
|
74cc34696e | ||
|
|
d4baac0bb5 | ||
|
|
35bc1421f1 | ||
|
|
d4db265fd9 | ||
|
|
1dad919de9 | ||
|
|
246dfbdcb4 | ||
|
|
f8d32d64f5 | ||
|
|
5dea271d6f | ||
|
|
eeb62a6cf2 | ||
|
|
35cf8026b0 | ||
|
|
e0028ab6f1 | ||
|
|
a32645cdeb | ||
|
|
812f9f6fca | ||
|
|
f7a670ec24 | ||
|
|
d0d24f0f4a | ||
|
|
042f9b7f2d | ||
|
|
2d260cdbed | ||
|
|
6a786cad83 | ||
|
|
67019b3d6c | ||
|
|
1db6e59077 | ||
|
|
5e4770875e | ||
|
|
e9a77f3f16 | ||
|
|
cbec85f295 | ||
|
|
14bd5d301d | ||
|
|
321d0e8d64 | ||
|
|
84e1512031 | ||
|
|
b036852b2d | ||
|
|
f693dc31e8 | ||
|
|
af8f5b11b8 | ||
|
|
8ca943f87b | ||
|
|
35cc9da626 | ||
|
|
44cc86a1a5 | ||
|
|
7c3bbfd45e | ||
|
|
a1f939e3a0 | ||
|
|
4ca7886090 | ||
|
|
b942163748 | ||
|
|
5b6d15acb3 | ||
|
|
841420360e | ||
|
|
a680bb4612 | ||
|
|
f763e13996 | ||
|
|
e73e1262ae | ||
|
|
b774d56cf7 | ||
|
|
bae55f2e8b | ||
|
|
6c16cdb011 | ||
|
|
86fcbb0354 | ||
|
|
17d030e800 | ||
|
|
6fbf28b30d | ||
|
|
8171b68b18 | ||
|
|
d30e3a4052 | ||
|
|
87aab7ac5b | ||
|
|
c46f5805b1 | ||
|
|
dd6a29dfc0 | ||
|
|
a0933c7f10 | ||
|
|
492adc2909 | ||
|
|
90a52f57b5 | ||
|
|
a1469854e8 | ||
|
|
e2c2993255 | ||
|
|
270d63b265 | ||
|
|
1d004be91d | ||
|
|
b8a74c727e | ||
|
|
c87b592277 | ||
|
|
cfa926602a | ||
|
|
350cb52c07 | ||
|
|
af195beb7e | ||
|
|
cb00d42546 | ||
|
|
ee0b0c3dfe | ||
|
|
ddcb4a0e10 | ||
|
|
8cbb29ee25 | ||
|
|
9da11ac144 | ||
|
|
ba7c8e77e5 | ||
|
|
4577b03fc9 | ||
|
|
72d83aa85e | ||
|
|
8ee80cb5f1 | ||
|
|
4cc08bff8b | ||
|
|
295cfb2d75 | ||
|
|
7775376b33 | ||
|
|
9f64e994dc | ||
|
|
ee1e4fc710 | ||
|
|
5ea62c710d | ||
|
|
aeca31d06a | ||
|
|
9cb9ea6ab5 | ||
|
|
e37dd69827 | ||
|
|
6c51696d1a | ||
|
|
27787c8f37 | ||
|
|
e910595545 | ||
|
|
a616739805 | ||
|
|
bea28de6a0 | ||
|
|
4e198ca2f0 | ||
|
|
2fbd16a0e3 | ||
|
|
76fc49f037 | ||
|
|
139c99440f | ||
|
|
137b9dfa0b | ||
|
|
5f0fdd15eb | ||
|
|
61e1427b83 | ||
|
|
b3aa0ba47c | ||
|
|
56e2b44c25 | ||
|
|
4d5a17583f | ||
|
|
71eda5aa3d | ||
|
|
0711ea8dc8 | ||
|
|
be206872d1 | ||
|
|
fcf3fe8dcd | ||
|
|
62dbd4062a | ||
|
|
196e8b4380 | ||
|
|
551e1255ff | ||
|
|
e09b61d1ac | ||
|
|
ee23bcc783 | ||
|
|
3e351bd8d3 | ||
|
|
0d3bc22d73 | ||
|
|
d82898421e | ||
|
|
1db2f0c2c5 | ||
|
|
6cd8a2203e |
@@ -1,4 +1,7 @@
|
||||
.git
|
||||
.idea
|
||||
/bin
|
||||
/dist
|
||||
/docs
|
||||
/npm-debug.log
|
||||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
||||
.idea
|
||||
7
.gitpod.yml
Normal file
7
.gitpod.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
tasks:
|
||||
- before: nvm install 10 && nvm use 10
|
||||
init: npm install
|
||||
command: npm run start
|
||||
ports:
|
||||
- port: 8080
|
||||
onOpen: open-preview
|
||||
27
Dockerfile
27
Dockerfile
@@ -1,21 +1,28 @@
|
||||
FROM node:10.13.0
|
||||
|
||||
RUN apt-get update && apt-get install -y nasm
|
||||
FROM node:10.15.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 \
|
||||
libpng-dev \
|
||||
&& npm install --production \
|
||||
&& apk del .build-dependencies
|
||||
|
||||
# Bundle app source
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8080
|
||||
CMD [ "node", "src/www" ]
|
||||
CMD [ "node", "./src/www" ]
|
||||
|
||||
32
README.md
32
README.md
@@ -1,37 +1,49 @@
|
||||
# Trilium Notes
|
||||
|
||||
[](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:
|
||||
|
||||

|
||||
|
||||
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)
|
||||
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation), full text search and [note hoisting](https://github.com/zadam/trilium/wiki/Note-hoisting)
|
||||
* 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
|
||||
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
|
||||
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
|
||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
|
||||
|
||||
## 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, Mac) or web application hosted on your server (Linux).
|
||||
|
||||
* 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 use Trilium on the desktop, download binary release for your platform 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Contribute
|
||||
|
||||
Use a browser based dev environment
|
||||
|
||||
[](https://gitpod.io/#https://github.com/zadam/trilium)
|
||||
|
||||
Or clone locally and run
|
||||
```
|
||||
npm install
|
||||
npm run start
|
||||
```
|
||||
@@ -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 .
|
||||
24
bin/build-linux-x64.sh
Executable file
24
bin/build-linux-x64.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BUILD_DIR=./dist/trilium-linux-x64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
rm -r node_modules/sqlite3/lib/binding/*
|
||||
|
||||
cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
||||
|
||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
|
||||
|
||||
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
|
||||
|
||||
cp src/public/images/app-icons/png/128x128.png $BUILD_DIR/icon.png
|
||||
|
||||
# removing software WebGL binaries because they are pretty huge and not necessary
|
||||
rm -r $BUILD_DIR/swiftshader
|
||||
|
||||
echo "Packaging linux x64 electron distribution..."
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
|
||||
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
|
||||
32
bin/build-mac-x64.sh
Executable file
32
bin/build-mac-x64.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BUILD_DIR=./dist/trilium-mac-x64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
echo "Copying required mac binaries"
|
||||
|
||||
rm -r node_modules/sqlite3/lib/binding/*
|
||||
rm -r node_modules/mozjpeg/vendor/*
|
||||
rm -r node_modules/pngquant-bin/vendor/*
|
||||
rm -r node_modules/giflossy/vendor/*
|
||||
|
||||
cp -r bin/deps/mac-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
||||
cp bin/deps/mac-x64/image/cjpeg node_modules/mozjpeg/vendor/
|
||||
cp bin/deps/mac-x64/image/pngquant node_modules/pngquant-bin/vendor/
|
||||
cp bin/deps/mac-x64/image/gifsicle node_modules/giflossy/vendor/
|
||||
|
||||
./node_modules/.bin/electron-packager . --asar --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
|
||||
|
||||
./reset-local.sh
|
||||
|
||||
echo "Zipping mac x64 electron distribution..."
|
||||
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
|
||||
rm trilium-mac-x64-${VERSION}.zip
|
||||
zip -r9 --symlinks trilium-mac-x64-${VERSION}.zip trilium-mac-x64
|
||||
@@ -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.15.0
|
||||
|
||||
rm -r $PKG_DIR
|
||||
mkdir $PKG_DIR
|
||||
@@ -30,9 +24,15 @@ cp -r ../../config-sample.ini ./
|
||||
|
||||
rm -r ./node_modules/electron*
|
||||
|
||||
rm -r ./node_modules/sqlite3/lib/binding/*
|
||||
|
||||
cp -r ../../bin/deps/linux-x64/sqlite/node* ./node_modules/sqlite3/lib/binding/
|
||||
|
||||
printf "#/bin/sh\n./node/bin/node src/www" > trilium.sh
|
||||
chmod 755 trilium.sh
|
||||
|
||||
cd ..
|
||||
|
||||
7z a trilium-linux-x64-server-${VERSION}.7z trilium-linux-x64-server
|
||||
VERSION=`jq -r ".version" ../package.json`
|
||||
|
||||
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server
|
||||
32
bin/build-win-x64.sh
Executable file
32
bin/build-win-x64.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BUILD_DIR=./dist/trilium-windows-x64
|
||||
rm -rf $BUILD_DIR
|
||||
|
||||
echo "Copying required windows binaries"
|
||||
|
||||
rm -r node_modules/sqlite3/lib/binding/*
|
||||
rm -r node_modules/mozjpeg/vendor/*
|
||||
rm -r node_modules/pngquant-bin/vendor/*
|
||||
rm -r node_modules/giflossy/vendor/*
|
||||
|
||||
cp -r bin/deps/win-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
||||
cp bin/deps/win-x64/image/cjpeg.exe node_modules/mozjpeg/vendor/
|
||||
cp bin/deps/win-x64/image/pngquant.exe node_modules/pngquant-bin/vendor/
|
||||
cp bin/deps/win-x64/image/gifsicle.exe node_modules/giflossy/vendor/
|
||||
|
||||
./node_modules/.bin/electron-packager . --asar --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
|
||||
|
||||
# removing software WebGL binaries because they are pretty huge and not necessary
|
||||
rm -r $BUILD_DIR/swiftshader
|
||||
|
||||
./reset-local.sh
|
||||
|
||||
echo "Zipping windows x64 electron distribution..."
|
||||
VERSION=`jq -r ".version" package.json`
|
||||
|
||||
cd dist
|
||||
|
||||
zip -r9 trilium-windows-x64-${VERSION}.zip trilium-windows-x64
|
||||
35
bin/build.sh
35
bin/build.sh
@@ -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-win-x64.sh
|
||||
|
||||
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=ia32 --overwrite
|
||||
bin/build-mac-x64.sh
|
||||
|
||||
mv "./dist/Trilium Notes-linux-ia32" ./dist/trilium-linux-ia32
|
||||
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development
|
||||
bin/build-linux-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
|
||||
bin/build-server.sh
|
||||
BIN
bin/deps/linux-x64/sqlite/electron-v4.0-linux-x64/node_sqlite3.node
Executable file
BIN
bin/deps/linux-x64/sqlite/electron-v4.0-linux-x64/node_sqlite3.node
Executable file
Binary file not shown.
BIN
bin/deps/linux-x64/sqlite/node-v64-linux-x64/node_sqlite3.node
Executable file
BIN
bin/deps/linux-x64/sqlite/node-v64-linux-x64/node_sqlite3.node
Executable file
Binary file not shown.
BIN
bin/deps/mac-x64/image/cjpeg
Normal file
BIN
bin/deps/mac-x64/image/cjpeg
Normal file
Binary file not shown.
BIN
bin/deps/mac-x64/image/gifsicle
Normal file
BIN
bin/deps/mac-x64/image/gifsicle
Normal file
Binary file not shown.
BIN
bin/deps/mac-x64/image/pngquant
Normal file
BIN
bin/deps/mac-x64/image/pngquant
Normal file
Binary file not shown.
Binary file not shown.
0
bin/generate-cert.sh
Normal file → Executable file
0
bin/generate-cert.sh
Normal file → Executable 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
|
||||
@@ -42,18 +42,22 @@ 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
|
||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.7z
|
||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.tar.xz
|
||||
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.zip
|
||||
MAC_X64_BUILD=trilium-mac-x64-$VERSION.zip
|
||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.tar.xz
|
||||
|
||||
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"
|
||||
|
||||
@@ -62,13 +66,6 @@ github-release upload \
|
||||
--name "$LINUX_X64_BUILD" \
|
||||
--file "dist/$LINUX_X64_BUILD"
|
||||
|
||||
echo "Uploading linux ia32 build"
|
||||
|
||||
github-release upload \
|
||||
--tag $TAG \
|
||||
--name "$LINUX_IA32_BUILD" \
|
||||
--file "dist/$LINUX_IA32_BUILD"
|
||||
|
||||
echo "Uploading windows x64 build"
|
||||
|
||||
github-release upload \
|
||||
@@ -76,9 +73,14 @@ github-release upload \
|
||||
--name "$WINDOWS_X64_BUILD" \
|
||||
--file "dist/$WINDOWS_X64_BUILD"
|
||||
|
||||
echo "Packaging server version"
|
||||
echo "Uploading mac x64 build"
|
||||
|
||||
bin/build-server.sh $VERSION
|
||||
github-release upload \
|
||||
--tag $TAG \
|
||||
--name "$MAC_X64_BUILD" \
|
||||
--file "dist/$MAC_X64_BUILD"
|
||||
|
||||
echo "Uploading linux x64 server build"
|
||||
|
||||
github-release upload \
|
||||
--tag $TAG \
|
||||
|
||||
3
bin/reset-local.sh
Executable file
3
bin/reset-local.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
./node_modules/.bin/electron-rebuild --arch=x64
|
||||
BIN
db/demo.tar
BIN
db/demo.tar
Binary file not shown.
@@ -0,0 +1 @@
|
||||
UPDATE attributes SET name = 'archived' where name = 'hideInAutocomplete';
|
||||
2
db/migrations/0121__add_hoisting_option.sql
Normal file
2
db/migrations/0121__add_hoisting_option.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
VALUES ('hoistedNoteId', 'root', '2018-12-11T18:31:00.874Z', '2018-12-11T18:31:00.874Z', 0);
|
||||
62
db/migrations/0122__add_iv_to_columns.js
Normal file
62
db/migrations/0122__add_iv_to_columns.js
Normal file
@@ -0,0 +1,62 @@
|
||||
const sql = require('../../src/services/sql');
|
||||
|
||||
function prependIv(cipherText, ivText) {
|
||||
const arr = ivText.split("").map(c => parseInt(c) || 0);
|
||||
const iv = Buffer.from(arr);
|
||||
const payload = Buffer.from(cipherText, 'base64');
|
||||
const complete = Buffer.concat([iv, payload]);
|
||||
|
||||
return complete.toString('base64');
|
||||
}
|
||||
|
||||
async function updateEncryptedDataKey() {
|
||||
const encryptedDataKey = await sql.getValue("SELECT value FROM options WHERE name = 'encryptedDataKey'");
|
||||
const encryptedDataKeyIv = await sql.getValue("SELECT value FROM options WHERE name = 'encryptedDataKeyIv'");
|
||||
|
||||
const newEncryptedDataKey = prependIv(encryptedDataKey, encryptedDataKeyIv);
|
||||
|
||||
await sql.execute("UPDATE options SET value = ? WHERE name = 'encryptedDataKey'", [newEncryptedDataKey]);
|
||||
|
||||
await sql.execute("DELETE FROM options WHERE name = 'encryptedDataKeyIv'");
|
||||
await sql.execute("DELETE FROM sync WHERE entityName = 'options' AND entityId = 'encryptedDataKeyIv'");
|
||||
}
|
||||
|
||||
async function updateNotes() {
|
||||
const protectedNotes = await sql.getRows("SELECT noteId, title, content FROM notes WHERE isProtected = 1");
|
||||
|
||||
for (const note of protectedNotes) {
|
||||
if (note.title !== null) {
|
||||
note.title = prependIv(note.title, "0" + note.noteId);
|
||||
}
|
||||
|
||||
if (note.content !== null) {
|
||||
note.content = prependIv(note.content, "1" + note.noteId);
|
||||
}
|
||||
|
||||
await sql.execute("UPDATE notes SET title = ?, content = ? WHERE noteId = ?", [note.title, note.content, note.noteId]);
|
||||
}
|
||||
}
|
||||
|
||||
async function updateNoteRevisions() {
|
||||
const protectedNoteRevisions = await sql.getRows("SELECT noteRevisionId, title, content FROM note_revisions WHERE isProtected = 1");
|
||||
|
||||
for (const noteRevision of protectedNoteRevisions) {
|
||||
if (noteRevision.title !== null) {
|
||||
noteRevision.title = prependIv(noteRevision.title, "0" + noteRevision.noteRevisionId);
|
||||
}
|
||||
|
||||
if (noteRevision.content !== null) {
|
||||
noteRevision.content = prependIv(noteRevision.content, "1" + noteRevision.noteRevisionId);
|
||||
}
|
||||
|
||||
await sql.execute("UPDATE note_revisions SET title = ?, content = ? WHERE noteRevisionId = ?", [noteRevision.title, noteRevision.content, noteRevision.noteRevisionId]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async () => {
|
||||
await updateEncryptedDataKey();
|
||||
|
||||
await updateNotes();
|
||||
|
||||
await updateNoteRevisions();
|
||||
};
|
||||
8
db/migrations/0123__add_options_for_font_sizes.sql
Normal file
8
db/migrations/0123__add_options_for_font_sizes.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
VALUES ('mainFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
|
||||
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
VALUES ('treeFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
|
||||
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
VALUES ('detailFontSize', '110', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
|
||||
11
db/migrations/0124__readd_font_sizes.sql
Normal file
11
db/migrations/0124__readd_font_sizes.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
SELECT 'mainFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
|
||||
WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'mainFontSize');
|
||||
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
SELECT 'treeFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
|
||||
WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'treeFontSize');
|
||||
|
||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
|
||||
SELECT 'detailFontSize', '110', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
|
||||
WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'detailFontSize');
|
||||
@@ -3010,7 +3010,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line234">line 234</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line236">line 236</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -133,6 +133,11 @@ class Attribute extends Entity {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.isOwned;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Attribute;</code></pre>
|
||||
|
||||
@@ -87,6 +87,11 @@ class Branch extends Entity {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.origParentNoteId;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Branch;</code></pre>
|
||||
|
||||
@@ -32,6 +32,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';
|
||||
@@ -102,7 +103,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 */
|
||||
@@ -394,6 +397,16 @@ class Note extends Entity {
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, label is either set or removed.
|
||||
*
|
||||
@@ -451,24 +464,32 @@ class Note extends Entity {
|
||||
async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
* @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 getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
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 child notes with given attribute name and value. Only own attributes are considered, not inherited ones
|
||||
* 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 = "";
|
||||
|
||||
@@ -500,22 +521,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.
|
||||
@@ -615,10 +636,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;
|
||||
}
|
||||
@@ -633,6 +650,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;</code></pre>
|
||||
|
||||
@@ -253,6 +253,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.
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line16">line 16</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line17">line 17</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line22">line 22</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line23">line 23</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line24">line 24</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line25">line 25</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line20">line 20</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line21">line 21</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -573,7 +573,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line41">line 41</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line42">line 42</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -726,7 +726,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line33">line 33</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line34">line 34</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -879,7 +879,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line60">line 60</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line61">line 61</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1057,7 +1057,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line197">line 197</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line198">line 198</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1188,7 +1188,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line157">line 157</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line158">line 158</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1292,7 +1292,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line221">line 221</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line222">line 222</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1396,7 +1396,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line203">line 203</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line204">line 204</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1500,7 +1500,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line215">line 215</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line216">line 216</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1609,7 +1609,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line150">line 150</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line151">line 151</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1808,7 +1808,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line142">line 142</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line143">line 143</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1957,7 +1957,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line209">line 209</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line210">line 210</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2088,7 +2088,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line164">line 164</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line165">line 165</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2196,7 +2196,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line188">line 188</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line189">line 189</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2373,7 +2373,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line110">line 110</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line111">line 111</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2526,7 +2526,138 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line227">line 227</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line228">line 228</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="setupElementTooltip"><span class="type-signature"></span>setupElementTooltip<span class="signature">($el)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>$el</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">jquery object on which to setup the tooltip</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line234">line 234</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2661,7 +2792,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line180">line 180</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line181">line 181</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2796,7 +2927,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line172">line 172</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line173">line 173</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
84
docs/frontend_api/entities_attribute.js.html
Normal file
84
docs/frontend_api/entities_attribute.js.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: entities/attribute.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: entities/attribute.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>class Attribute {
|
||||
constructor(treeCache, row) {
|
||||
this.treeCache = treeCache;
|
||||
/** @param {string} attributeId */
|
||||
this.attributeId = row.attributeId;
|
||||
/** @param {string} noteId */
|
||||
this.noteId = row.noteId;
|
||||
/** @param {string} type */
|
||||
this.type = row.type;
|
||||
/** @param {string} name */
|
||||
this.name = row.name;
|
||||
/** @param {string} value */
|
||||
this.value = row.value;
|
||||
/** @param {int} position */
|
||||
this.position = row.position;
|
||||
/** @param {boolean} isInheritable */
|
||||
this.isInheritable = row.isInheritable;
|
||||
/** @param {boolean} isDeleted */
|
||||
this.isDeleted = row.isDeleted;
|
||||
/** @param {string} dateCreated */
|
||||
this.dateCreated = row.dateCreated;
|
||||
/** @param {string} dateModified */
|
||||
this.dateModified = row.dateModified;
|
||||
}
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
async getNote() {
|
||||
return await this.treeCache.getNote(this.noteId);
|
||||
}
|
||||
|
||||
get toString() {
|
||||
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
|
||||
}
|
||||
}</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -42,7 +42,7 @@ class Branch {
|
||||
/** @param {string} */
|
||||
this.prefix = row.prefix;
|
||||
/** @param {boolean} */
|
||||
this.isExpanded = row.isExpanded;
|
||||
this.isExpanded = !!row.isExpanded;
|
||||
}
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
|
||||
@@ -26,7 +26,14 @@
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/**
|
||||
<pre class="prettyprint source linenums"><code>import server from '../services/server.js';
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
const RELATION = 'relation';
|
||||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* This note's representation is used in note tree and is kept in TreeCache.
|
||||
* Its notable omission is the note content.
|
||||
*/
|
||||
@@ -99,6 +106,140 @@ class NoteShort {
|
||||
return await this.treeCache.getNotes(this.getChildNoteIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @returns {Promise<Attribute[]>}
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
if (!this.attributeCache) {
|
||||
this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
|
||||
}
|
||||
|
||||
if (name) {
|
||||
return this.attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.attributeCache;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited)
|
||||
*/
|
||||
async hasAttribute(type, name) {
|
||||
return !!await this.getAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
|
||||
*/
|
||||
async getAttribute(type, name) {
|
||||
const attributes = await this.getAttributes();
|
||||
|
||||
return attributes.find(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getAttributeValue(type, name) {
|
||||
const attr = await this.getAttribute(type, name);
|
||||
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (including inherited)
|
||||
*/
|
||||
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (including inherited)
|
||||
*/
|
||||
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute>} label if it exists, null otherwise
|
||||
*/
|
||||
async getLabel(name) { return await this.getAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getRelation(name) { return await this.getAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.attributeCache = null;
|
||||
}
|
||||
|
||||
get toString() {
|
||||
return `Note(noteId=${this.noteId}, title=${this.title})`;
|
||||
}
|
||||
@@ -107,6 +248,7 @@ class NoteShort {
|
||||
const dto = Object.assign({}, this);
|
||||
delete dto.treeCache;
|
||||
delete dto.archived;
|
||||
delete dto.attributeCache;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line47">line 47</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line48">line 48</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import linkService from './link.js';
|
||||
import treeCache from './tree_cache.js';
|
||||
import noteDetailService from './note_detail.js';
|
||||
import noteTypeService from './note_type.js';
|
||||
import noteTooltipService from './note_tooltip.js';
|
||||
|
||||
/**
|
||||
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
||||
@@ -253,6 +254,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
|
||||
* @param {array} types - list of mime types to be used
|
||||
*/
|
||||
this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @param {object} $el - jquery object on which to setup the tooltip
|
||||
*/
|
||||
this.setupElementTooltip = noteTooltipService.setupElementTooltip
|
||||
}
|
||||
|
||||
export default FrontendScriptApi;</code></pre>
|
||||
|
||||
@@ -81,7 +81,7 @@ app.on('ready', async () => {
|
||||
const dateNoteService = require('./src/services/date_notes');
|
||||
const dateUtils = require('./src/services/date_utils');
|
||||
|
||||
const parentNote = await dateNoteService.getDateNote(dateUtils.nowDate());
|
||||
const parentNote = await dateNoteService.getDateNote(dateUtils.nowLocalDate());
|
||||
|
||||
// window may be hidden / not in focus
|
||||
mainWindow.focus();
|
||||
|
||||
5
issue_template.md
Normal file
5
issue_template.md
Normal file
@@ -0,0 +1,5 @@
|
||||
For bug reports, please mention **version of the application** and include **log files** from following location:
|
||||
|
||||
* `/home/[user]/.local/share/trilium-data/log` for Linux
|
||||
* `C:\Users\[user]\AppData\Roaming\trilium-data\log` for Windows Vista and up
|
||||
* `/Users/[user]/Library/Application Support/trilium-data/log` for Mac OS
|
||||
519
package-lock.json
generated
519
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.24.3-beta",
|
||||
"version": "0.27.4",
|
||||
"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": "10.12.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
|
||||
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
|
||||
"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",
|
||||
@@ -670,9 +671,9 @@
|
||||
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
|
||||
},
|
||||
"asar": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/asar/-/asar-0.14.5.tgz",
|
||||
"integrity": "sha512-2Di/TnY1sridHFKMFgxBh0Wk0gVxSZN4qQhRhjJn3UywZAvP5MHI0RNVSkpzmJ+n6t0BC8w/+1257wtSgQ3Kdg==",
|
||||
"version": "0.14.6",
|
||||
"resolved": "https://registry.npmjs.org/asar/-/asar-0.14.6.tgz",
|
||||
"integrity": "sha512-ZqybKcdO5At6y3ge2RHxVImc6Eltb2t3sxT7lk4T4zjZBSFUuIGCIZY6f41dCjlvJSizN5QPRr8YTgMhpgBjLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
@@ -681,7 +682,7 @@
|
||||
"glob": "^6.0.4",
|
||||
"minimatch": "^3.0.3",
|
||||
"mkdirp": "^0.5.0",
|
||||
"mksnapshot": "^0.3.0",
|
||||
"mksnapshot": "^0.3.4",
|
||||
"tmp": "0.0.28"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -968,7 +969,8 @@
|
||||
"bluebird": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
|
||||
"integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg=="
|
||||
"integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==",
|
||||
"dev": true
|
||||
},
|
||||
"bmp-js": {
|
||||
"version": "0.1.0",
|
||||
@@ -1818,9 +1820,9 @@
|
||||
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
|
||||
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
},
|
||||
@@ -2033,7 +2035,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||
"dev": true
|
||||
}
|
||||
@@ -2202,6 +2204,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,12 +2375,12 @@
|
||||
"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.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.1.tgz",
|
||||
"integrity": "sha512-kBWDLn1Vq8Tm6+/HpQc8gkjX7wJyQI8v/lf2kAirfi0Q4cXh6vBjozFvV1U/9gGCbyKnIDM+m8/wpyJIjg4w7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "^8.0.24",
|
||||
"@types/node": "^10.12.18",
|
||||
"electron-download": "^4.1.0",
|
||||
"extract-zip": "^1.0.3"
|
||||
}
|
||||
@@ -2524,10 +2527,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-notarize": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-0.0.5.tgz",
|
||||
"integrity": "sha512-YzrqZ6RDQ7Wt2RWlxzRoQUuxnTeXrfp7laH7XKcmQqrZ6GaAr50DMPvFMpqDKdrZSHSbcgZgB7ktIQbjvITmCQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.0",
|
||||
"fs-extra": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"electron-osx-sign": {
|
||||
"version": "0.4.10",
|
||||
"resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.10.tgz",
|
||||
"integrity": "sha1-vk87ibKnWh3F8eckkIGrKSnKOiY=",
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz",
|
||||
"integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.5.0",
|
||||
@@ -2535,7 +2548,7 @@
|
||||
"debug": "^2.6.8",
|
||||
"isbinaryfile": "^3.0.2",
|
||||
"minimist": "^1.2.0",
|
||||
"plist": "^2.1.0"
|
||||
"plist": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -2550,69 +2563,50 @@
|
||||
}
|
||||
},
|
||||
"electron-packager": {
|
||||
"version": "12.2.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-12.2.0.tgz",
|
||||
"integrity": "sha512-T5W/FIK4VXhYIOWxkehmz6zXt2S/sA9JZ3AL+/jeKCicQY6QVQ0K8B7W801L+GPTwbgTPycHjO+iqEf1BhZ+Iw==",
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-13.0.1.tgz",
|
||||
"integrity": "sha512-fXfldaZ1wihpPaMTSGMxvCeETJwVArlnMmKafVXLJbbZwS+WTjY4iL7ju9WMQ0LNGuiiIwSMCQFxt5iA087mqg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asar": "^0.14.0",
|
||||
"debug": "^3.0.0",
|
||||
"debug": "^4.0.1",
|
||||
"electron-download": "^4.1.1",
|
||||
"electron-osx-sign": "^0.4.1",
|
||||
"electron-notarize": "^0.0.5",
|
||||
"electron-osx-sign": "^0.4.11",
|
||||
"extract-zip": "^1.0.3",
|
||||
"fs-extra": "^5.0.0",
|
||||
"fs-extra": "^7.0.0",
|
||||
"galactus": "^0.2.1",
|
||||
"get-package-info": "^1.0.0",
|
||||
"nodeify": "^1.0.1",
|
||||
"parse-author": "^2.0.0",
|
||||
"pify": "^3.0.0",
|
||||
"plist": "^2.0.0",
|
||||
"pify": "^4.0.0",
|
||||
"plist": "^3.0.0",
|
||||
"rcedit": "^1.0.0",
|
||||
"resolve": "^1.1.6",
|
||||
"sanitize-filename": "^1.6.0",
|
||||
"semver": "^5.3.0",
|
||||
"yargs-parser": "^10.0.0"
|
||||
"yargs-parser": "^11.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"camelcase": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
|
||||
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"pify": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
|
||||
"integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
|
||||
"version": "11.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
|
||||
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase": "^4.1.0"
|
||||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3876,9 +3870,9 @@
|
||||
}
|
||||
},
|
||||
"file-type": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
|
||||
"integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU="
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-10.7.0.tgz",
|
||||
"integrity": "sha512-AbaGtdWYYRaVrv2MwL/65myuRJ9j3e79e7etJ79US18QHuVlzJBcQHUH+HxDUoLtbyWRTUfLzLkGXX3pP9kfZg=="
|
||||
},
|
||||
"filename-regex": {
|
||||
"version": "2.0.1",
|
||||
@@ -4303,7 +4297,7 @@
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||
"dev": true
|
||||
},
|
||||
@@ -4337,9 +4331,9 @@
|
||||
}
|
||||
},
|
||||
"get-port": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-port/-/get-port-4.0.0.tgz",
|
||||
"integrity": "sha512-Yy3yNI2oShgbaWg4cmPhWjkZfktEvpKI09aDX4PZzNtlU9obuYrX7x2mumQsrNxlF+Ls7OtMQW/u+X4s896bOQ=="
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-port/-/get-port-4.1.0.tgz",
|
||||
"integrity": "sha512-4/fqAYrzrzOiqDrdeZRKXGdTGgbkfTEumGlNQPeP6Jy8w0PzN9mzeNQ3XgHaTNie8pQ3hOUkrwlZt2Fzk5H9mA=="
|
||||
},
|
||||
"get-proxy": {
|
||||
"version": "1.1.0",
|
||||
@@ -4903,7 +4897,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 +4960,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",
|
||||
@@ -5004,6 +5000,13 @@
|
||||
"integrity": "sha1-FQKvMTX5BuEiyHfDHpSve3qRRsU=",
|
||||
"requires": {
|
||||
"file-type": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"file-type": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
|
||||
"integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU="
|
||||
}
|
||||
}
|
||||
},
|
||||
"imagemin": {
|
||||
@@ -5604,12 +5607,6 @@
|
||||
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
|
||||
"integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
|
||||
},
|
||||
"is-promise": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz",
|
||||
"integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=",
|
||||
"dev": true
|
||||
},
|
||||
"is-proto-prop": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-1.0.1.tgz",
|
||||
@@ -5750,14 +5747,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 +6414,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": {
|
||||
@@ -6531,19 +6535,19 @@
|
||||
"dev": true
|
||||
},
|
||||
"mksnapshot": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/mksnapshot/-/mksnapshot-0.3.1.tgz",
|
||||
"integrity": "sha1-JQHAVldDbXQs6Vik/5LHfkDdN+Y=",
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/mksnapshot/-/mksnapshot-0.3.4.tgz",
|
||||
"integrity": "sha512-FgUTiWiY+35LgL95P/MDYrBuQO5o0s3MmaWKX6ZJWoX4vMOY9vPsAv763l1OSSelL9jPsBQ/wf4bzfqTLNPSFg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"decompress-zip": "0.3.0",
|
||||
"fs-extra": "0.26.7",
|
||||
"request": "^2.79.0"
|
||||
"request": "2.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": {
|
||||
"version": "0.26.7",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
|
||||
"resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
|
||||
"integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@@ -6571,9 +6575,9 @@
|
||||
"integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE="
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.22.2",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
|
||||
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
|
||||
"version": "2.23.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz",
|
||||
"integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA=="
|
||||
},
|
||||
"mozjpeg": {
|
||||
"version": "6.0.1",
|
||||
@@ -7197,10 +7201,9 @@
|
||||
"integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA="
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "2.4.5",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz",
|
||||
"integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==",
|
||||
"dev": true,
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.1.tgz",
|
||||
"integrity": "sha512-oDbFc7vCFx0RWWCweTer3hFm1u+e60N5FtGnmRV6QqvgATGFH/XRR6vqWIeBVosCYCqt6YdIr2L0exLZuEdVcQ==",
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
@@ -7275,16 +7278,6 @@
|
||||
"resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
|
||||
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
|
||||
},
|
||||
"nodeify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz",
|
||||
"integrity": "sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-promise": "~1.0.0",
|
||||
"promise": "~1.3.0"
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
|
||||
@@ -7770,9 +7763,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",
|
||||
@@ -8030,26 +8023,20 @@
|
||||
"integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
|
||||
},
|
||||
"plist": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
|
||||
"integrity": "sha1-V8zbeggh3yGDEhejytVOPhRqECU=",
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
|
||||
"integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"base64-js": "1.2.0",
|
||||
"xmlbuilder": "8.2.2",
|
||||
"base64-js": "^1.2.3",
|
||||
"xmlbuilder": "^9.0.7",
|
||||
"xmldom": "0.1.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
|
||||
"integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=",
|
||||
"dev": true
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
|
||||
"integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
|
||||
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -8479,15 +8466,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"promise": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "http://registry.npmjs.org/promise/-/promise-1.3.0.tgz",
|
||||
"integrity": "sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-promise": "~1"
|
||||
}
|
||||
},
|
||||
"proto-list": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||
@@ -8815,17 +8793,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-promise": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
|
||||
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
|
||||
"requires": {
|
||||
"bluebird": "^3.5.0",
|
||||
"request-promise-core": "1.1.1",
|
||||
"stealthy-require": "^1.1.0",
|
||||
"tough-cookie": ">=2.3.3"
|
||||
}
|
||||
},
|
||||
"request-promise-core": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
|
||||
@@ -9218,9 +9185,9 @@
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||
},
|
||||
"simple-node-logger": {
|
||||
"version": "0.93.40",
|
||||
"resolved": "https://registry.npmjs.org/simple-node-logger/-/simple-node-logger-0.93.40.tgz",
|
||||
"integrity": "sha512-ByWh6D6DgXteLICr5Bhca5CIDxuGt7xOysulWPIrBcwTT6ZCNF4SrwmtIDhC+cSNlJsz/fGytn7mH2Zqyh9euA==",
|
||||
"version": "18.12.21",
|
||||
"resolved": "https://registry.npmjs.org/simple-node-logger/-/simple-node-logger-18.12.21.tgz",
|
||||
"integrity": "sha512-I2dA9JLiNrdTsmOI2bT0mIQNEKhTKbj9OM8tny3Il/5R6QdJHlWrv1NDdS+6UQHEnYV1413FnwgqTjzmV0ctCw==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.10",
|
||||
"moment": "^2.20.1"
|
||||
|
||||
27
package.json
27
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.24.4-beta",
|
||||
"version": "0.28.3",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -17,7 +17,8 @@
|
||||
"start-electron": "electron . --disable-gpu",
|
||||
"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"
|
||||
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
||||
"postinstall": "electron-builder install-app-deps"
|
||||
},
|
||||
"dependencies": {
|
||||
"async-mutex": "0.1.3",
|
||||
@@ -26,16 +27,16 @@
|
||||
"cls-hooked": "4.2.2",
|
||||
"commonmark": "0.28.1",
|
||||
"cookie-parser": "1.4.3",
|
||||
"debug": "4.1.0",
|
||||
"devtron": "1.4.0",
|
||||
"debug": "4.1.1",
|
||||
"ejs": "2.6.1",
|
||||
"electron-debug": "2.0.0",
|
||||
"electron-dl": "1.12.0",
|
||||
"electron-in-page-search": "1.3.2",
|
||||
"express": "4.16.4",
|
||||
"express-session": "1.15.6",
|
||||
"file-type": "10.7.0",
|
||||
"fs-extra": "7.0.1",
|
||||
"get-port": "4.0.0",
|
||||
"get-port": "4.1.0",
|
||||
"helmet": "3.15.0",
|
||||
"html": "1.0.0",
|
||||
"image-type": "3.0.0",
|
||||
@@ -44,20 +45,20 @@
|
||||
"imagemin-mozjpeg": "8.0.0",
|
||||
"imagemin-pngquant": "6.0.0",
|
||||
"ini": "1.3.5",
|
||||
"jimp": "0.5.6",
|
||||
"moment": "2.22.2",
|
||||
"jimp": "0.6.0",
|
||||
"mime-types": "^2.1.21",
|
||||
"moment": "2.23.0",
|
||||
"multer": "1.4.1",
|
||||
"node-abi": "2.5.1",
|
||||
"open": "0.0.5",
|
||||
"rand-token": "0.4.0",
|
||||
"rcedit": "1.1.1",
|
||||
"request": "2.88.0",
|
||||
"request-promise": "4.2.2",
|
||||
"rimraf": "2.6.2",
|
||||
"sanitize-filename": "1.6.1",
|
||||
"sax": "^1.2.4",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.2.0",
|
||||
"simple-node-logger": "0.93.40",
|
||||
"simple-node-logger": "18.12.21",
|
||||
"sqlite": "3.0.0",
|
||||
"tar-stream": "1.6.2",
|
||||
"turndown": "5.0.1",
|
||||
@@ -66,9 +67,11 @@
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "4.0.0-beta.7",
|
||||
"devtron": "1.4.0",
|
||||
"electron": "4.0.1",
|
||||
"electron-builder": "20.38.4",
|
||||
"electron-compile": "6.4.3",
|
||||
"electron-packager": "12.2.0",
|
||||
"electron-packager": "13.0.1",
|
||||
"electron-rebuild": "1.8.2",
|
||||
"lorem-ipsum": "1.0.6",
|
||||
"tape": "4.9.1",
|
||||
|
||||
@@ -105,6 +105,11 @@ class Attribute extends Entity {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.isOwned;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Attribute;
|
||||
@@ -59,6 +59,11 @@ class Branch extends Entity {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.origParentNoteId;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Branch;
|
||||
@@ -15,7 +15,8 @@ const ENTITY_NAME_TO_ENTITY = {
|
||||
"note_revisions": NoteRevision,
|
||||
"recent_notes": RecentNote,
|
||||
"options": Option,
|
||||
"api_tokens": ApiToken
|
||||
"api_tokens": ApiToken,
|
||||
"links": Link
|
||||
};
|
||||
|
||||
function getEntityFromEntityName(entityName) {
|
||||
|
||||
@@ -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';
|
||||
@@ -46,7 +47,18 @@ class Note extends Entity {
|
||||
if (this.isProtected && this.noteId) {
|
||||
this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
|
||||
|
||||
protectedSessionService.decryptNote(this);
|
||||
if (this.isContentAvailable) {
|
||||
protectedSessionService.decryptNote(this);
|
||||
}
|
||||
else {
|
||||
// saving ciphertexts in case we do want to update protected note outside of protected session
|
||||
// (which is allowed)
|
||||
this.titleCipherText = this.title;
|
||||
this.contentCipherText = this.content;
|
||||
|
||||
this.title = "[protected]";
|
||||
this.content = "";
|
||||
}
|
||||
}
|
||||
|
||||
this.setContent(this.content);
|
||||
@@ -55,6 +67,9 @@ class Note extends Entity {
|
||||
setContent(content) {
|
||||
this.content = content;
|
||||
|
||||
// if parsing below is not successful then there's no jsonContent as opposed to still having the old unupdated ones
|
||||
delete this.jsonContent;
|
||||
|
||||
try {
|
||||
this.jsonContent = JSON.parse(this.content);
|
||||
}
|
||||
@@ -74,7 +89,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 */
|
||||
@@ -366,6 +383,16 @@ class Note extends Entity {
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, label is either set or removed.
|
||||
*
|
||||
@@ -423,24 +450,32 @@ class Note extends Entity {
|
||||
async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
* @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 getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
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 child notes with given attribute name and value. Only own attributes are considered, not inherited ones
|
||||
* 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 +507,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 +622,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 +636,26 @@ class Note extends Entity {
|
||||
this.dateModified = dateUtils.nowDate();
|
||||
}
|
||||
}
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
if (pojo.isProtected) {
|
||||
if (this.isContentAvailable) {
|
||||
protectedSessionService.encryptNote(pojo);
|
||||
}
|
||||
else {
|
||||
// updating protected note outside of protected session means we will keep original ciphertexts
|
||||
pojo.title = pojo.titleCipherText;
|
||||
pojo.content = pojo.contentCipherText;
|
||||
}
|
||||
}
|
||||
|
||||
delete pojo.jsonContent;
|
||||
delete pojo.isContentAvailable;
|
||||
delete pojo.__attributeCache;
|
||||
delete pojo.titleCipherText;
|
||||
delete pojo.contentCipherText;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Note;
|
||||
BIN
src/public/images/app-icons/mac/icon.icns
Normal file
BIN
src/public/images/app-icons/mac/icon.icns
Normal file
Binary file not shown.
@@ -1,36 +1,42 @@
|
||||
import addLinkDialog from '../dialogs/add_link.js';
|
||||
import jumpToNoteDialog from '../dialogs/jump_to_note.js';
|
||||
import attributesDialog from '../dialogs/attributes.js';
|
||||
import noteRevisionsDialog from '../dialogs/note_revisions.js';
|
||||
import noteSourceDialog from '../dialogs/note_source.js';
|
||||
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 addLinkDialog from './dialogs/add_link.js';
|
||||
import jumpToNoteDialog from './dialogs/jump_to_note.js';
|
||||
import attributesDialog from './dialogs/attributes.js';
|
||||
import noteRevisionsDialog from './dialogs/note_revisions.js';
|
||||
import noteSourceDialog from './dialogs/note_source.js';
|
||||
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';
|
||||
import dragAndDropSetup from './drag_and_drop.js';
|
||||
import exportService from './export.js';
|
||||
import link from './link.js';
|
||||
import messagingService from './messaging.js';
|
||||
import noteDetailService from './note_detail.js';
|
||||
import noteType from './note_type.js';
|
||||
import protected_session from './protected_session.js';
|
||||
import searchNotesService from './search_notes.js';
|
||||
import FrontendScriptApi from './frontend_script_api.js';
|
||||
import ScriptContext from './script_context.js';
|
||||
import sync from './sync.js';
|
||||
import treeService from './tree.js';
|
||||
import treeChanges from './branches.js';
|
||||
import treeUtils from './tree_utils.js';
|
||||
import utils from './utils.js';
|
||||
import server from './server.js';
|
||||
import entrypoints from './entrypoints.js';
|
||||
import tooltip from './tooltip.js';
|
||||
import bundle from "./bundle.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
import libraryLoader from "./library_loader.js";
|
||||
import cloning from './services/cloning.js';
|
||||
import contextMenu from './services/tree_context_menu.js';
|
||||
import dragAndDropSetup from './services/drag_and_drop.js';
|
||||
import exportService from './services/export.js';
|
||||
import link from './services/link.js';
|
||||
import messagingService from './services/messaging.js';
|
||||
import noteDetailService from './services/note_detail.js';
|
||||
import noteType from './services/note_type.js';
|
||||
import protected_session from './services/protected_session.js';
|
||||
import searchNotesService from './services/search_notes.js';
|
||||
import FrontendScriptApi from './services/frontend_script_api.js';
|
||||
import ScriptContext from './services/script_context.js';
|
||||
import sync from './services/sync.js';
|
||||
import treeService from './services/tree.js';
|
||||
import treeChanges from './services/branches.js';
|
||||
import treeUtils from './services/tree_utils.js';
|
||||
import utils from './services/utils.js';
|
||||
import server from './services/server.js';
|
||||
import entrypoints from './services/entrypoints.js';
|
||||
import noteTooltipService from './services/note_tooltip.js';
|
||||
import bundle from "./services/bundle.js";
|
||||
import treeCache from "./services/tree_cache.js";
|
||||
import libraryLoader from "./services/library_loader.js";
|
||||
import hoistedNoteService from './services/hoisted_note.js';
|
||||
import noteTypeService from './services/note_type.js';
|
||||
import linkService from './services/link.js';
|
||||
import noteAutocompleteService from './services/note_autocomplete.js';
|
||||
import macInit from './services/mac_init.js';
|
||||
|
||||
// required for CKEditor image upload plugin
|
||||
window.glob.getCurrentNode = treeService.getCurrentNode;
|
||||
@@ -83,6 +89,8 @@ $(document).on("click", "button[data-help-page]", e => {
|
||||
|
||||
$("#logout-button").toggle(!utils.isElectron());
|
||||
|
||||
$("#tree").on("click", ".unhoist-button", hoistedNoteService.unhoist);
|
||||
|
||||
if (utils.isElectron()) {
|
||||
require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
|
||||
// this might occur when day note had to be created
|
||||
@@ -103,18 +111,26 @@ 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');
|
||||
});
|
||||
|
||||
macInit.init();
|
||||
|
||||
treeService.showTree();
|
||||
|
||||
entrypoints.registerEntrypoints();
|
||||
|
||||
tooltip.setupTooltip();
|
||||
noteTooltipService.setupGlobalTooltip();
|
||||
|
||||
bundle.executeStartupBundles();
|
||||
bundle.executeStartupBundles();
|
||||
|
||||
noteTypeService.init();
|
||||
|
||||
linkService.init();
|
||||
|
||||
noteAutocompleteService.init();
|
||||
@@ -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 : {
|
||||
@@ -168,6 +169,8 @@ function AttributesModel() {
|
||||
infoService.showMessage("Attributes have been saved.");
|
||||
|
||||
attributeService.refreshAttributes();
|
||||
|
||||
noteDetailService.reload();
|
||||
};
|
||||
|
||||
function addLastEmptyRow() {
|
||||
@@ -187,7 +190,8 @@ function AttributesModel() {
|
||||
labelDefinition: {
|
||||
labelType: "text",
|
||||
multiplicityType: "singlevalue",
|
||||
isPromoted: true
|
||||
isPromoted: true,
|
||||
numberPrecision: 0
|
||||
},
|
||||
relationDefinition: {
|
||||
multiplicityType: "singlevalue",
|
||||
|
||||
@@ -2,6 +2,7 @@ import treeService from '../services/tree.js';
|
||||
import server from '../services/server.js';
|
||||
import treeCache from "../services/tree_cache.js";
|
||||
import treeUtils from "../services/tree_utils.js";
|
||||
import infoService from "../services/info.js";
|
||||
|
||||
const $dialog = $("#branch-prefix-dialog");
|
||||
const $form = $("#branch-prefix-form");
|
||||
@@ -24,7 +25,7 @@ async function showDialog() {
|
||||
|
||||
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
|
||||
|
||||
$noteTitle.html(noteTitle);
|
||||
$noteTitle.text(" - " + noteTitle);
|
||||
}
|
||||
|
||||
async function savePrefix() {
|
||||
@@ -35,6 +36,8 @@ async function savePrefix() {
|
||||
await treeService.setPrefix(branchId, prefix);
|
||||
|
||||
$dialog.modal('hide');
|
||||
|
||||
infoService.showMessage("Branch prefix has been saved.");
|
||||
}
|
||||
|
||||
$form.submit(() => {
|
||||
|
||||
77
src/public/javascripts/dialogs/export.js
Normal file
77
src/public/javascripts/dialogs/export.js
Normal 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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -6,8 +6,6 @@ const $dialog = $("#jump-to-note-dialog");
|
||||
const $autoComplete = $("#jump-to-note-autocomplete");
|
||||
const $showInFullTextButton = $("#show-in-full-text-button");
|
||||
|
||||
$dialog.on("shown.bs.modal", e => $autoComplete.focus());
|
||||
|
||||
async function showDialog() {
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ addTabHandler((function() {
|
||||
const $zoomFactorSelect = $("#zoom-factor-select");
|
||||
const $leftPaneMinWidth = $("#left-pane-min-width");
|
||||
const $leftPaneWidthPercent = $("#left-pane-width-percent");
|
||||
const $html = $("html");
|
||||
const $mainFontSize = $("#main-font-size");
|
||||
const $treeFontSize = $("#tree-font-size");
|
||||
const $detailFontSize = $("#detail-font-size");
|
||||
const $body = $("body");
|
||||
const $container = $("#container");
|
||||
|
||||
function optionsLoaded(options) {
|
||||
@@ -59,21 +62,27 @@ addTabHandler((function() {
|
||||
|
||||
$leftPaneMinWidth.val(options.leftPaneMinWidth);
|
||||
$leftPaneWidthPercent.val(options.leftPaneWidthPercent);
|
||||
|
||||
$mainFontSize.val(options.mainFontSize);
|
||||
$treeFontSize.val(options.treeFontSize);
|
||||
$detailFontSize.val(options.detailFontSize);
|
||||
}
|
||||
|
||||
$themeSelect.change(function() {
|
||||
const newTheme = $(this).val();
|
||||
|
||||
$html.attr("class", "theme-" + newTheme);
|
||||
for (const clazz of $body[0].classList) {
|
||||
if (clazz.startsWith("theme-")) {
|
||||
$body.removeClass(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
$body.addClass("theme-" + newTheme);
|
||||
|
||||
server.put('options/theme/' + newTheme);
|
||||
});
|
||||
|
||||
$zoomFactorSelect.change(function() {
|
||||
const newZoomFactor = $(this).val();
|
||||
|
||||
zoomService.setZoomFactorAndSave(newZoomFactor);
|
||||
});
|
||||
$zoomFactorSelect.change(function() { zoomService.setZoomFactorAndSave($(this).val()); });
|
||||
|
||||
function resizeLeftPanel() {
|
||||
const leftPanePercent = parseInt($leftPaneWidthPercent.val());
|
||||
@@ -83,20 +92,42 @@ addTabHandler((function() {
|
||||
$container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
|
||||
}
|
||||
|
||||
$leftPaneMinWidth.change(function() {
|
||||
const newMinWidth = $(this).val();
|
||||
$leftPaneMinWidth.change(async function() {
|
||||
await server.put('options/leftPaneMinWidth/' + $(this).val());
|
||||
|
||||
resizeLeftPanel();
|
||||
|
||||
server.put('options/leftPaneMinWidth/' + newMinWidth);
|
||||
});
|
||||
|
||||
$leftPaneWidthPercent.change(function() {
|
||||
const newWidthPercent = $(this).val();
|
||||
$leftPaneWidthPercent.change(async function() {
|
||||
await server.put('options/leftPaneWidthPercent/' + $(this).val());
|
||||
|
||||
resizeLeftPanel();
|
||||
});
|
||||
|
||||
server.put('options/leftPaneWidthPercent/' + newWidthPercent);
|
||||
function applyFontSizes() {
|
||||
console.log($mainFontSize.val() + "% !important");
|
||||
|
||||
$body.get(0).style.setProperty("--main-font-size", $mainFontSize.val() + "%");
|
||||
$body.get(0).style.setProperty("--tree-font-size", $treeFontSize.val() + "%");
|
||||
$body.get(0).style.setProperty("--detail-font-size", $detailFontSize.val() + "%");
|
||||
}
|
||||
|
||||
$mainFontSize.change(async function() {
|
||||
await server.put('options/mainFontSize/' + $(this).val());
|
||||
|
||||
applyFontSizes();
|
||||
});
|
||||
|
||||
$treeFontSize.change(async function() {
|
||||
await server.put('options/treeFontSize/' + $(this).val());
|
||||
|
||||
applyFontSizes();
|
||||
});
|
||||
|
||||
$detailFontSize.change(async function() {
|
||||
await server.put('options/detailFontSize/' + $(this).val());
|
||||
|
||||
applyFontSizes();
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -198,15 +229,17 @@ addTabHandler((async function () {
|
||||
const $syncVersion = $("#sync-version");
|
||||
const $buildDate = $("#build-date");
|
||||
const $buildRevision = $("#build-revision");
|
||||
const $dataDirectory = $("#data-directory");
|
||||
|
||||
const appInfo = await server.get('app-info');
|
||||
|
||||
$appVersion.html(appInfo.appVersion);
|
||||
$dbVersion.html(appInfo.dbVersion);
|
||||
$syncVersion.html(appInfo.syncVersion);
|
||||
$buildDate.html(appInfo.buildDate);
|
||||
$buildRevision.html(appInfo.buildRevision);
|
||||
$appVersion.text(appInfo.appVersion);
|
||||
$dbVersion.text(appInfo.dbVersion);
|
||||
$syncVersion.text(appInfo.syncVersion);
|
||||
$buildDate.text(appInfo.buildDate);
|
||||
$buildRevision.text(appInfo.buildRevision);
|
||||
$buildRevision.attr('href', 'https://github.com/zadam/trilium/commit/' + appInfo.buildRevision);
|
||||
$dataDirectory.text(appInfo.dataDirectory);
|
||||
|
||||
return {};
|
||||
})());
|
||||
|
||||
36
src/public/javascripts/entities/attribute.js
Normal file
36
src/public/javascripts/entities/attribute.js
Normal file
@@ -0,0 +1,36 @@
|
||||
class Attribute {
|
||||
constructor(treeCache, row) {
|
||||
this.treeCache = treeCache;
|
||||
/** @param {string} attributeId */
|
||||
this.attributeId = row.attributeId;
|
||||
/** @param {string} noteId */
|
||||
this.noteId = row.noteId;
|
||||
/** @param {string} type */
|
||||
this.type = row.type;
|
||||
/** @param {string} name */
|
||||
this.name = row.name;
|
||||
/** @param {string} value */
|
||||
this.value = row.value;
|
||||
/** @param {int} position */
|
||||
this.position = row.position;
|
||||
/** @param {boolean} isInheritable */
|
||||
this.isInheritable = row.isInheritable;
|
||||
/** @param {boolean} isDeleted */
|
||||
this.isDeleted = row.isDeleted;
|
||||
/** @param {string} dateCreated */
|
||||
this.dateCreated = row.dateCreated;
|
||||
/** @param {string} dateModified */
|
||||
this.dateModified = row.dateModified;
|
||||
}
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
async getNote() {
|
||||
return await this.treeCache.getNote(this.noteId);
|
||||
}
|
||||
|
||||
get toString() {
|
||||
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
|
||||
}
|
||||
}
|
||||
|
||||
export default Attribute;
|
||||
@@ -14,7 +14,7 @@ class Branch {
|
||||
/** @param {string} */
|
||||
this.prefix = row.prefix;
|
||||
/** @param {boolean} */
|
||||
this.isExpanded = row.isExpanded;
|
||||
this.isExpanded = !!row.isExpanded;
|
||||
}
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
import server from '../services/server.js';
|
||||
|
||||
const LABEL = 'label';
|
||||
const LABEL_DEFINITION = 'label-definition';
|
||||
const RELATION = 'relation';
|
||||
const RELATION_DEFINITION = 'relation-definition';
|
||||
|
||||
/**
|
||||
* This note's representation is used in note tree and is kept in TreeCache.
|
||||
* Its notable omission is the note content.
|
||||
@@ -71,6 +78,140 @@ class NoteShort {
|
||||
return await this.treeCache.getNotes(this.getChildNoteIds());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @returns {Promise<Attribute[]>}
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
if (!this.attributeCache) {
|
||||
this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
|
||||
}
|
||||
|
||||
if (name) {
|
||||
return this.attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.attributeCache;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited)
|
||||
*/
|
||||
async hasAttribute(type, name) {
|
||||
return !!await this.getAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
|
||||
*/
|
||||
async getAttribute(type, name) {
|
||||
const attributes = await this.getAttributes();
|
||||
|
||||
return attributes.find(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getAttributeValue(type, name) {
|
||||
const attr = await this.getAttribute(type, name);
|
||||
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (including inherited)
|
||||
*/
|
||||
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (including inherited)
|
||||
*/
|
||||
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute>} label if it exists, null otherwise
|
||||
*/
|
||||
async getLabel(name) { return await this.getAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getRelation(name) { return await this.getAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getRelationTarget(name) {
|
||||
const relation = await this.getRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.attributeCache = null;
|
||||
}
|
||||
|
||||
get toString() {
|
||||
return `Note(noteId=${this.noteId}, title=${this.title})`;
|
||||
}
|
||||
@@ -79,6 +220,7 @@ class NoteShort {
|
||||
const dto = Object.assign({}, this);
|
||||
delete dto.treeCache;
|
||||
delete dto.archived;
|
||||
delete dto.attributeCache;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
128
src/public/javascripts/mobile.js
Normal file
128
src/public/javascripts/mobile.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import treeService from "./services/tree.js";
|
||||
import noteDetailService from "./services/note_detail.js";
|
||||
import dragAndDropSetup from "./services/drag_and_drop.js";
|
||||
import treeCache from "./services/tree_cache.js";
|
||||
import treeBuilder from "./services/tree_builder.js";
|
||||
import contextMenuWidget from "./services/context_menu.js";
|
||||
import ContextMenuItemsContainer from "./services/context_menu_items_container.js";
|
||||
import treeChangesService from "./services/branches.js";
|
||||
import utils from "./services/utils.js";
|
||||
import treeUtils from "./services/tree_utils.js";
|
||||
|
||||
const $leftPane = $("#left-pane");
|
||||
const $tree = $("#tree");
|
||||
const $detail = $("#detail");
|
||||
const $closeDetailButton = $("#close-detail-button");
|
||||
|
||||
function togglePanes() {
|
||||
if (!$leftPane.is(":visible") || !$detail.is(":visible")) {
|
||||
$detail.toggleClass("d-none");
|
||||
$leftPane.toggleClass("d-none");
|
||||
}
|
||||
}
|
||||
|
||||
function showDetailPane() {
|
||||
if (!$detail.is(":visible")) {
|
||||
$detail.removeClass("d-none");
|
||||
$leftPane.addClass("d-none");
|
||||
}
|
||||
}
|
||||
|
||||
$closeDetailButton.click(() => {
|
||||
// no page is opened
|
||||
document.location.hash = '-';
|
||||
|
||||
togglePanes();
|
||||
});
|
||||
|
||||
async function showTree() {
|
||||
const tree = await treeService.loadTree();
|
||||
|
||||
$tree.fancytree({
|
||||
autoScroll: true,
|
||||
extensions: ["dnd5", "clones"],
|
||||
source: tree,
|
||||
scrollParent: $tree,
|
||||
minExpandLevel: 2, // root can't be collapsed
|
||||
activate: (event, data) => {
|
||||
const node = data.node;
|
||||
const noteId = node.data.noteId;
|
||||
|
||||
treeService.clearSelectedNodes();
|
||||
|
||||
treeService.setCurrentNotePathToHash(node);
|
||||
|
||||
showDetailPane();
|
||||
|
||||
noteDetailService.switchToNote(noteId, true);
|
||||
},
|
||||
expand: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, true),
|
||||
collapse: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, false),
|
||||
init: (event, data) => treeService.treeInitialized(), // don't collapse to short form
|
||||
dnd5: dragAndDropSetup,
|
||||
lazyLoad: function(event, data) {
|
||||
const noteId = data.node.data.noteId;
|
||||
|
||||
data.result = treeCache.getNote(noteId).then(note => treeBuilder.prepareBranch(note));
|
||||
},
|
||||
clones: {
|
||||
highlightActiveClones: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$("#note-menu-button").click(async e => {
|
||||
const node = treeService.getCurrentNode();
|
||||
const branch = await treeCache.getBranch(node.data.branchId);
|
||||
const note = await treeCache.getNote(node.data.noteId);
|
||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||
const isNotRoot = note.noteId !== 'root';
|
||||
|
||||
const itemsContainer = new ContextMenuItemsContainer([
|
||||
{title: "Insert note after", cmd: "insertNoteAfter", uiIcon: "plus"},
|
||||
{title: "Insert child note", cmd: "insertChildNote", uiIcon: "plus"},
|
||||
{title: "Delete this note", cmd: "delete", uiIcon: "trash"}
|
||||
]);
|
||||
|
||||
itemsContainer.enableItem("insertNoteAfter", isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("insertChildNote", note.type !== 'search');
|
||||
itemsContainer.enableItem("delete", isNotRoot && parentNote.type !== 'search');
|
||||
|
||||
contextMenuWidget.initContextMenu(e, itemsContainer, (event, cmd) => {
|
||||
if (cmd === "insertNoteAfter") {
|
||||
const parentNoteId = node.data.parentNoteId;
|
||||
const isProtected = treeUtils.getParentProtectedStatus(node);
|
||||
|
||||
treeService.createNote(node, parentNoteId, 'after', isProtected);
|
||||
}
|
||||
else if (cmd === "insertChildNote") {
|
||||
treeService.createNote(node, node.data.noteId, 'into');
|
||||
}
|
||||
else if (cmd === "delete") {
|
||||
treeChangesService.deleteNodes([node]);
|
||||
|
||||
// move to the tree
|
||||
togglePanes();
|
||||
}
|
||||
else {
|
||||
throw new Error("Unrecognized command " + cmd);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#switch-to-desktop-button").click(() => {
|
||||
utils.setCookie('trilium-device', 'desktop');
|
||||
|
||||
utils.reloadApp();
|
||||
});
|
||||
|
||||
$("#log-out-button").click(() => {
|
||||
$("#logout-form").submit();
|
||||
});
|
||||
|
||||
// this is done so that startNotePath is not used
|
||||
if (!document.location.hash) {
|
||||
document.location.hash = '-';
|
||||
}
|
||||
|
||||
showTree();
|
||||
@@ -10,9 +10,9 @@ 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
|
||||
@@ -25,10 +25,6 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
|
||||
return {name};
|
||||
});
|
||||
|
||||
if (result.length === 0) {
|
||||
result.push({name: "No results"});
|
||||
}
|
||||
|
||||
cb(result);
|
||||
}
|
||||
}]);
|
||||
@@ -57,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) {
|
||||
|
||||
@@ -3,24 +3,35 @@ 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;
|
||||
|
||||
async function refreshAttributes() {
|
||||
function invalidateAttributes() {
|
||||
attributePromise = null;
|
||||
}
|
||||
|
||||
function reloadAttributes() {
|
||||
attributePromise = server.get('notes/' + noteDetailService.getCurrentNoteId() + '/attributes');
|
||||
}
|
||||
|
||||
async function refreshAttributes() {
|
||||
reloadAttributes();
|
||||
|
||||
await showAttributes();
|
||||
}
|
||||
|
||||
async function getAttributes() {
|
||||
if (!attributePromise) {
|
||||
reloadAttributes();
|
||||
}
|
||||
|
||||
return await attributePromise;
|
||||
}
|
||||
|
||||
@@ -74,8 +85,11 @@ async function showAttributes() {
|
||||
$promotedAttributesContainer.empty().append($tbody);
|
||||
}
|
||||
else if (note.type !== 'relation-map') {
|
||||
if (attributes.length > 0) {
|
||||
for (const attribute of attributes) {
|
||||
// display only "own" notes
|
||||
const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
|
||||
|
||||
if (ownedAttributes.length > 0) {
|
||||
for (const attribute of ownedAttributes) {
|
||||
if (attribute.type === 'label') {
|
||||
$attributeListInner.append(utils.formatLabel(attribute) + " ");
|
||||
}
|
||||
@@ -121,7 +135,9 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
|
||||
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
|
||||
|
||||
const $actionCell = $("<td>");
|
||||
const $multiplicityCell = $("<td>").addClass("multiplicity");
|
||||
const $multiplicityCell = $("<td>")
|
||||
.addClass("multiplicity")
|
||||
.attr("nowrap", true);
|
||||
|
||||
$tr
|
||||
.append($labelCell)
|
||||
@@ -144,9 +160,10 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
|
||||
$input.autocomplete({
|
||||
appendTo: document.querySelector('body'),
|
||||
hint: false,
|
||||
autoselect: true,
|
||||
autoselect: false,
|
||||
openOnFocus: true,
|
||||
minLength: 0
|
||||
minLength: 0,
|
||||
tabAutocomplete: false
|
||||
}, [{
|
||||
displayKey: 'value',
|
||||
source: function (term, cb) {
|
||||
@@ -161,6 +178,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,11 +292,17 @@ 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 {
|
||||
getAttributes,
|
||||
showAttributes,
|
||||
refreshAttributes
|
||||
refreshAttributes,
|
||||
invalidateAttributes
|
||||
}
|
||||
@@ -9,7 +9,7 @@ async function getAndExecuteBundle(noteId, originEntity = null) {
|
||||
}
|
||||
|
||||
async function executeBundle(bundle, originEntity) {
|
||||
const apiContext = ScriptContext(bundle.note, bundle.allNotes, originEntity);
|
||||
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity);
|
||||
|
||||
try {
|
||||
return await (function () {
|
||||
@@ -30,9 +30,13 @@ async function executeStartupBundles() {
|
||||
}
|
||||
|
||||
async function executeRelationBundles(note, relationName) {
|
||||
const bundlesToRun = await server.get("script/relation/" + note.noteId + "/" + relationName);
|
||||
note.bundleCache = note.bundleCache || {};
|
||||
|
||||
for (const bundle of bundlesToRun) {
|
||||
if (!note.bundleCache[relationName]) {
|
||||
note.bundleCache[relationName] = await server.get("script/relation/" + note.noteId + "/" + relationName);
|
||||
}
|
||||
|
||||
for (const bundle of note.bundleCache[relationName]) {
|
||||
await executeBundle(bundle, note);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
const $contextMenuContainer = $("#context-menu-container");
|
||||
|
||||
function initContextMenu(event, contextMenuItems, selectContextMenuItem) {
|
||||
function initContextMenu(event, itemContainer, selectContextMenuItem) {
|
||||
event.stopPropagation();
|
||||
|
||||
$contextMenuContainer.empty();
|
||||
|
||||
for (const item of contextMenuItems) {
|
||||
for (const item of itemContainer.getItems()) {
|
||||
if (item.title === '----') {
|
||||
$contextMenuContainer.append($("<div>").addClass("dropdown-divider"));
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
class ContextMenuItemsContainer {
|
||||
constructor(items) {
|
||||
// clone the item array and the items themselves
|
||||
this.items = items.map(item => Object.assign({}, item));
|
||||
}
|
||||
|
||||
hideItem(cmd, hidden = true) {
|
||||
if (hidden) {
|
||||
this.items = this.items.filter(item => item.cmd !== cmd);
|
||||
}
|
||||
}
|
||||
|
||||
enableItem(cmd, enabled) {
|
||||
const item = this.items.find(item => item.cmd === cmd);
|
||||
|
||||
if (!item) {
|
||||
throw new Error(`Command ${cmd} has not been found!`);
|
||||
}
|
||||
|
||||
item.enabled = enabled;
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return this.items;
|
||||
}
|
||||
}
|
||||
|
||||
export default ContextMenuItemsContainer;
|
||||
@@ -4,6 +4,7 @@ import treeChangesService from './branches.js';
|
||||
const dragAndDropSetup = {
|
||||
autoExpandMS: 600,
|
||||
dragStart: (node, data) => {
|
||||
// don't allow dragging root node
|
||||
if (node.data.noteId === 'root') {
|
||||
return false;
|
||||
}
|
||||
@@ -22,11 +23,7 @@ const dragAndDropSetup = {
|
||||
// Return false to cancel dragging of node.
|
||||
return true;
|
||||
},
|
||||
dragEnter: (node, data) => {
|
||||
// we don't allow moving root to any other location in the tree
|
||||
// we allow it to be placed on the relation map though, that's handled in a different drop handler
|
||||
return node.data.noteId === 'root';
|
||||
}, // allow drop on any node
|
||||
dragEnter: (node, data) => true, // allow drop on any node
|
||||
dragDrop: (node, data) => {
|
||||
// This function MUST be defined to enable dropping of items on the tree.
|
||||
// data.hitMode is 'before', 'after', or 'over'.
|
||||
|
||||
@@ -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);
|
||||
@@ -87,7 +87,7 @@ function registerEntrypoints() {
|
||||
|
||||
utils.bindShortcut('ctrl+r', utils.reloadApp);
|
||||
|
||||
$(document).bind('keydown', 'ctrl+shift+i', () => {
|
||||
utils.bindShortcut('ctrl+shift+i', () => {
|
||||
if (utils.isElectron()) {
|
||||
require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
|
||||
@@ -95,7 +95,7 @@ function registerEntrypoints() {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).bind('keydown', 'ctrl+f', () => {
|
||||
function openInPageSearch() {
|
||||
if (utils.isElectron()) {
|
||||
const $searchWindowWebview = $(".electron-in-page-search-window");
|
||||
$searchWindowWebview.show();
|
||||
@@ -113,7 +113,9 @@ function registerEntrypoints() {
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
utils.bindShortcut('ctrl+f', openInPageSearch);
|
||||
|
||||
// FIXME: do we really need these at this point?
|
||||
utils.bindShortcut("ctrl+shift+up", () => {
|
||||
@@ -133,8 +135,8 @@ function registerEntrypoints() {
|
||||
});
|
||||
|
||||
if (utils.isElectron()) {
|
||||
$(document).bind('keydown', 'ctrl+-', zoomService.decreaseZoomFactor);
|
||||
$(document).bind('keydown', 'ctrl+=', zoomService.increaseZoomFactor);
|
||||
utils.bindShortcut('ctrl+-', zoomService.decreaseZoomFactor);
|
||||
utils.bindShortcut('ctrl+=', zoomService.increaseZoomFactor);
|
||||
}
|
||||
|
||||
$("#note-title").bind('keydown', 'return', () => $("#note-detail-text").focus());
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -6,6 +6,8 @@ import linkService from './link.js';
|
||||
import treeCache from './tree_cache.js';
|
||||
import noteDetailService from './note_detail.js';
|
||||
import noteTypeService from './note_type.js';
|
||||
import noteTooltipService from './note_tooltip.js';
|
||||
import protectedSessionService from'./protected_session.js';
|
||||
|
||||
/**
|
||||
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
||||
@@ -41,7 +43,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
|
||||
this.activateNewNote = async notePath => {
|
||||
await treeService.reload();
|
||||
|
||||
await treeService.activateNote(notePath, true);
|
||||
await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -202,6 +204,19 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
|
||||
*/
|
||||
this.getCurrentNoteContent = noteDetailService.getCurrentNoteContent;
|
||||
|
||||
/**
|
||||
* This method checks whether user navigated away from the note from which the scripts has been started.
|
||||
* This is necessary because script execution is async and by the time it is finished, the user might have
|
||||
* already navigated away from this page - the end result would be that script might return data for the wrong
|
||||
* note.
|
||||
*
|
||||
* @method
|
||||
* @return {boolean} returns true if the original note is still loaded, false if user switched to another
|
||||
*/
|
||||
this.isNoteStillLoaded = () => {
|
||||
return this.originEntity.noteId === noteDetailService.getCurrentNoteId();
|
||||
};
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @param {function} func - callback called on note change as user is typing (not necessarily tied to save event)
|
||||
@@ -225,6 +240,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
|
||||
* @param {array} types - list of mime types to be used
|
||||
*/
|
||||
this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @param {object} $el - jquery object on which to setup the tooltip
|
||||
*/
|
||||
this.setupElementTooltip = noteTooltipService.setupElementTooltip;
|
||||
|
||||
/**
|
||||
* @method
|
||||
*/
|
||||
this.protectCurrentNote = protectedSessionService.protectNoteAndSendToServer;
|
||||
}
|
||||
|
||||
export default FrontendScriptApi;
|
||||
33
src/public/javascripts/services/hoisted_note.js
Normal file
33
src/public/javascripts/services/hoisted_note.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import optionsInit from './options_init.js';
|
||||
import server from "./server.js";
|
||||
import tree from "./tree.js";
|
||||
|
||||
let hoistedNoteId;
|
||||
|
||||
optionsInit.optionsReady.then(options => {
|
||||
hoistedNoteId = options['hoistedNoteId'];
|
||||
});
|
||||
|
||||
async function getHoistedNoteId() {
|
||||
await optionsInit.optionsReady;
|
||||
|
||||
return hoistedNoteId;
|
||||
}
|
||||
|
||||
async function setHoistedNoteId(noteId) {
|
||||
hoistedNoteId = noteId;
|
||||
|
||||
await server.put('options/hoistedNoteId/' + noteId);
|
||||
|
||||
await tree.reload();
|
||||
}
|
||||
|
||||
async function unhoist() {
|
||||
await setHoistedNoteId('root');
|
||||
}
|
||||
|
||||
export default {
|
||||
getHoistedNoteId,
|
||||
setHoistedNoteId,
|
||||
unhoist
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -88,17 +88,19 @@ function addTextToEditor(text) {
|
||||
});
|
||||
}
|
||||
|
||||
ko.bindingHandlers.noteLink = {
|
||||
init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
const noteId = ko.unwrap(valueAccessor());
|
||||
function init() {
|
||||
ko.bindingHandlers.noteLink = {
|
||||
init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
const noteId = ko.unwrap(valueAccessor());
|
||||
|
||||
if (noteId) {
|
||||
const link = await createNoteLink(noteId);
|
||||
if (noteId) {
|
||||
const link = await createNoteLink(noteId);
|
||||
|
||||
$(element).append(link);
|
||||
$(element).append(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
|
||||
// of opening the link in new window/tab
|
||||
@@ -124,5 +126,6 @@ export default {
|
||||
getNotePathFromUrl,
|
||||
createNoteLink,
|
||||
addLinkToEditor,
|
||||
addTextToEditor
|
||||
addTextToEditor,
|
||||
init
|
||||
};
|
||||
25
src/public/javascripts/services/mac_init.js
Normal file
25
src/public/javascripts/services/mac_init.js
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Mac specific initialization
|
||||
*/
|
||||
import utils from "./utils.js";
|
||||
|
||||
function init() {
|
||||
if (utils.isElectron() && utils.isMac()) {
|
||||
utils.bindShortcut('meta+c', () => exec("copy"));
|
||||
utils.bindShortcut('meta+v', () => exec('paste'));
|
||||
utils.bindShortcut('meta+x', () => exec('cut'));
|
||||
utils.bindShortcut('meta+a', () => exec('selectAll'));
|
||||
utils.bindShortcut('meta+z', () => exec('undo'));
|
||||
utils.bindShortcut('meta+y', () => exec('redo'));
|
||||
}
|
||||
}
|
||||
|
||||
function exec(cmd) {
|
||||
document.execCommand(cmd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export default {
|
||||
init
|
||||
}
|
||||
@@ -28,7 +28,7 @@ function clearText($el) {
|
||||
function showRecentNotes($el) {
|
||||
$el.setSelectedPath("");
|
||||
$el.autocomplete("val", "");
|
||||
$el.autocomplete("open");
|
||||
$el.focus();
|
||||
}
|
||||
|
||||
function initNoteAutocomplete($el, options) {
|
||||
@@ -61,7 +61,13 @@ function initNoteAutocomplete($el, options) {
|
||||
|
||||
$clearTextButton.click(() => clearText($el));
|
||||
|
||||
$showRecentNotesButton.click(() => showRecentNotes($el));
|
||||
$showRecentNotesButton.click(e => {
|
||||
showRecentNotes($el);
|
||||
|
||||
// this will cause the click not give focus to the "show recent notes" button
|
||||
// this is important because otherwise input will lose focus immediatelly and not show the results
|
||||
return false;
|
||||
});
|
||||
|
||||
$goToSelectedNoteButton.click(() => {
|
||||
if ($el.hasClass("disabled")) {
|
||||
@@ -76,7 +82,8 @@ function initNoteAutocomplete($el, options) {
|
||||
hint: false,
|
||||
autoselect: true,
|
||||
openOnFocus: true,
|
||||
minLength: 0
|
||||
minLength: 0,
|
||||
tabAutocomplete: false
|
||||
}, [
|
||||
{
|
||||
source: autocompleteSource,
|
||||
@@ -100,40 +107,42 @@ function initNoteAutocomplete($el, options) {
|
||||
return $el;
|
||||
}
|
||||
|
||||
$.fn.getSelectedPath = function() {
|
||||
if (!$(this).val().trim()) {
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return $(this).attr(SELECTED_PATH_KEY);
|
||||
}
|
||||
};
|
||||
function init() {
|
||||
$.fn.getSelectedPath = function () {
|
||||
if (!$(this).val().trim()) {
|
||||
return "";
|
||||
} else {
|
||||
return $(this).attr(SELECTED_PATH_KEY);
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.setSelectedPath = function(path) {
|
||||
path = path || "";
|
||||
$.fn.setSelectedPath = function (path) {
|
||||
path = path || "";
|
||||
|
||||
$(this).attr(SELECTED_PATH_KEY, path);
|
||||
$(this).attr(SELECTED_PATH_KEY, path);
|
||||
|
||||
$(this)
|
||||
.closest(".input-group")
|
||||
.find(".go-to-selected-note-button")
|
||||
.toggleClass("disabled", !path.trim())
|
||||
.attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed
|
||||
};
|
||||
$(this)
|
||||
.closest(".input-group")
|
||||
.find(".go-to-selected-note-button")
|
||||
.toggleClass("disabled", !path.trim())
|
||||
.attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed
|
||||
};
|
||||
|
||||
ko.bindingHandlers.noteAutocomplete = {
|
||||
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
initNoteAutocomplete($(element));
|
||||
ko.bindingHandlers.noteAutocomplete = {
|
||||
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
|
||||
initNoteAutocomplete($(element));
|
||||
|
||||
$(element).setSelectedPath(bindingContext.$data.selectedPath);
|
||||
$(element).setSelectedPath(bindingContext.$data.selectedPath);
|
||||
|
||||
$(element).on('autocomplete:selected', function(event, suggestion, dataset) {
|
||||
bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : '';
|
||||
});
|
||||
}
|
||||
};
|
||||
$(element).on('autocomplete:selected', function (event, suggestion, dataset) {
|
||||
bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : '';
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
initNoteAutocomplete,
|
||||
showRecentNotes
|
||||
showRecentNotes,
|
||||
init
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import noteDetailRender from './note_detail_render.js';
|
||||
import noteDetailRelationMap from './note_detail_relation_map.js';
|
||||
import bundleService from "./bundle.js";
|
||||
import attributeService from "./attributes.js";
|
||||
import utils from "./utils.js";
|
||||
|
||||
const $noteTitle = $("#note-title");
|
||||
|
||||
@@ -28,6 +29,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;
|
||||
|
||||
@@ -35,6 +37,8 @@ let noteChangeDisabled = false;
|
||||
|
||||
let isNoteChanged = false;
|
||||
|
||||
let detailLoadedListeners = [];
|
||||
|
||||
const components = {
|
||||
'code': noteDetailCode,
|
||||
'text': noteDetailText,
|
||||
@@ -78,6 +82,8 @@ function noteChanged() {
|
||||
}
|
||||
|
||||
isNoteChanged = true;
|
||||
|
||||
$savedIndicator.fadeOut();
|
||||
}
|
||||
|
||||
async function reload() {
|
||||
@@ -105,6 +111,10 @@ function onNoteChange(func) {
|
||||
async function saveNote() {
|
||||
const note = getCurrentNote();
|
||||
|
||||
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
note.title = $noteTitle.val();
|
||||
note.content = getCurrentNoteContent(note);
|
||||
|
||||
@@ -120,28 +130,27 @@ async function saveNote() {
|
||||
protectedSessionHolder.touchProtectedSession();
|
||||
}
|
||||
|
||||
infoService.showMessage("Saved!");
|
||||
$savedIndicator.fadeIn();
|
||||
|
||||
// run async
|
||||
bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteChange');
|
||||
}
|
||||
|
||||
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) {
|
||||
$noteDetailWrapper.toggleClass("protected", note.isProtected);
|
||||
$protectButton.toggleClass("active", note.isProtected);
|
||||
$protectButton.prop("disabled", note.isProtected);
|
||||
$unprotectButton.toggleClass("active", !note.isProtected);
|
||||
$unprotectButton.prop("disabled", !protectedSessionHolder.isProtectedSessionAvailable());
|
||||
}
|
||||
|
||||
let isNewNoteCreated = false;
|
||||
|
||||
function newNoteCreated() {
|
||||
isNewNoteCreated = true;
|
||||
$unprotectButton.prop("disabled", !note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
|
||||
}
|
||||
|
||||
async function handleProtectedSession() {
|
||||
@@ -173,13 +182,13 @@ async function loadNoteDetail(noteId) {
|
||||
// only now that we're in sync with tree active node we will switch currentNote
|
||||
currentNote = loadedNote;
|
||||
|
||||
// needs to happend after loading the note itself because it references current noteId
|
||||
attributeService.refreshAttributes();
|
||||
|
||||
if (isNewNoteCreated) {
|
||||
isNewNoteCreated = false;
|
||||
|
||||
$noteTitle.focus().select();
|
||||
if (utils.isDesktop()) {
|
||||
// needs to happen after loading the note itself because it references current noteId
|
||||
attributeService.refreshAttributes();
|
||||
}
|
||||
else {
|
||||
// mobile usually doesn't need attributes so we just invalidate
|
||||
attributeService.invalidateAttributes();
|
||||
}
|
||||
|
||||
$noteIdDisplay.html(noteId);
|
||||
@@ -193,8 +202,10 @@ async function loadNoteDetail(noteId) {
|
||||
try {
|
||||
$noteTitle.val(currentNote.title);
|
||||
|
||||
noteTypeService.setNoteType(currentNote.type);
|
||||
noteTypeService.setNoteMime(currentNote.mime);
|
||||
if (utils.isDesktop()) {
|
||||
noteTypeService.setNoteType(currentNote.type);
|
||||
noteTypeService.setNoteMime(currentNote.mime);
|
||||
}
|
||||
|
||||
for (const componentType in components) {
|
||||
if (componentType !== currentNote.type) {
|
||||
@@ -210,6 +221,8 @@ async function loadNoteDetail(noteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
$noteTitle.removeAttr("readonly"); // this can be set by protected session service
|
||||
|
||||
await getComponent(currentNote.type).show();
|
||||
}
|
||||
finally {
|
||||
@@ -219,15 +232,19 @@ async function loadNoteDetail(noteId) {
|
||||
treeService.setBranchBackgroundBasedOnProtectedStatus(noteId);
|
||||
|
||||
// after loading new note make sure editor is scrolled to the top
|
||||
$noteDetailWrapper.scrollTop(0);
|
||||
getComponent(currentNote.type).scrollToTop();
|
||||
|
||||
fireDetailLoaded();
|
||||
|
||||
$scriptArea.empty();
|
||||
|
||||
await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView');
|
||||
|
||||
await attributeService.showAttributes();
|
||||
if (utils.isDesktop()) {
|
||||
await attributeService.showAttributes();
|
||||
|
||||
await showChildrenOverview();
|
||||
await showChildrenOverview();
|
||||
}
|
||||
}
|
||||
|
||||
async function showChildrenOverview() {
|
||||
@@ -270,6 +287,34 @@ function focusOnTitle() {
|
||||
$noteTitle.focus();
|
||||
}
|
||||
|
||||
function focusAndSelectTitle() {
|
||||
$noteTitle.focus().select();
|
||||
}
|
||||
|
||||
/**
|
||||
* Since detail loading may take some time and user might just browse through the notes using UP-DOWN keys,
|
||||
* we intentionally decouple activation of the note in the tree and full load of the note so just avaiting on
|
||||
* fancytree's activate() won't wait for the full load.
|
||||
*
|
||||
* This causes an issue where in some cases you want to do some action after detail is loaded. For this reason
|
||||
* we provide the listeners here which will be triggered after the detail is loaded and if the loaded note
|
||||
* is the one registered in the listener.
|
||||
*/
|
||||
function addDetailLoadedListener(noteId, callback) {
|
||||
detailLoadedListeners.push({ noteId, callback });
|
||||
}
|
||||
|
||||
function fireDetailLoaded() {
|
||||
for (const {noteId, callback} of detailLoadedListeners) {
|
||||
if (noteId === currentNote.noteId) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// all the listeners are one time only
|
||||
detailLoadedListeners = [];
|
||||
}
|
||||
|
||||
messagingService.subscribeToSyncMessages(syncData => {
|
||||
if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === getCurrentNoteId())) {
|
||||
infoService.showMessage('Reloading note because of background changes');
|
||||
@@ -294,7 +339,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,
|
||||
@@ -304,11 +349,12 @@ export default {
|
||||
getCurrentNote,
|
||||
getCurrentNoteType,
|
||||
getCurrentNoteId,
|
||||
newNoteCreated,
|
||||
focusOnTitle,
|
||||
focusAndSelectTitle,
|
||||
saveNote,
|
||||
saveNoteIfChanged,
|
||||
noteChanged,
|
||||
getCurrentNoteContent,
|
||||
onNoteChange
|
||||
onNoteChange,
|
||||
addDetailLoadedListener
|
||||
};
|
||||
@@ -3,6 +3,7 @@ import bundleService from "./bundle.js";
|
||||
import infoService from "./info.js";
|
||||
import server from "./server.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
import utils from "./utils.js";
|
||||
|
||||
let codeEditor = null;
|
||||
|
||||
@@ -94,7 +95,7 @@ function onNoteChange(func) {
|
||||
codeEditor.on('change', func);
|
||||
}
|
||||
|
||||
$(document).bind('keydown', "ctrl+return", executeCurrentNote);
|
||||
utils.bindShortcut("ctrl+return", executeCurrentNote);
|
||||
|
||||
$executeScriptButton.click(executeCurrentNote);
|
||||
|
||||
@@ -107,5 +108,6 @@ export default {
|
||||
if (codeEditor) {
|
||||
codeEditor.setValue('');
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollToTop: () => $component.scrollTop(0)
|
||||
}
|
||||
|
||||
@@ -53,5 +53,6 @@ export default {
|
||||
getContent: () => null,
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup: () => null
|
||||
cleanup: () => null,
|
||||
scrollToTop: () => null
|
||||
}
|
||||
@@ -71,5 +71,6 @@ export default {
|
||||
getContent: () => null,
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup: () => null
|
||||
cleanup: () => null,
|
||||
scrollToTop: () => $component.scrollTop(0)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import attributeAutocompleteService from "./attribute_autocomplete.js";
|
||||
import promptDialog from "../dialogs/prompt.js";
|
||||
import infoDialog from "../dialogs/info.js";
|
||||
import confirmDialog from "../dialogs/confirm.js";
|
||||
import ContextMenuItemsContainer from "./context_menu_items_container.js";
|
||||
|
||||
const $component = $("#note-detail-relation-map");
|
||||
const $relationMapContainer = $("#relation-map-container");
|
||||
@@ -80,7 +81,16 @@ const linkOverlays = [
|
||||
function loadMapData() {
|
||||
const currentNote = noteDetailService.getCurrentNote();
|
||||
mapData = {
|
||||
notes: []
|
||||
notes: [],
|
||||
// it is important to have this exact value here so that initial transform is same as this
|
||||
// which will guarantee note won't be saved on first conversion to relation map note type
|
||||
// this keeps the principle that note type change doesn't destroy note content unless user
|
||||
// does some actual change
|
||||
transform: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
scale: 1
|
||||
}
|
||||
};
|
||||
|
||||
if (currentNote.content) {
|
||||
@@ -304,9 +314,9 @@ function connectionContextMenuHandler(connection, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const contextMenuItems = [ {title: "Remove relation", cmd: "remove", uiIcon: "trash"} ];
|
||||
const contextMenuItemsContainer = new ContextMenuItemsContainer([ {title: "Remove relation", cmd: "remove", uiIcon: "trash"} ]);
|
||||
|
||||
contextMenuWidget.initContextMenu(event, contextMenuItems, async (event, cmd) => {
|
||||
contextMenuWidget.initContextMenu(event, contextMenuItemsContainer, async (event, cmd) => {
|
||||
if (cmd === 'remove') {
|
||||
if (!await confirmDialog.confirm("Are you sure you want to remove the relation?")) {
|
||||
return;
|
||||
@@ -380,12 +390,12 @@ async function connectionCreatedHandler(info, originalEvent) {
|
||||
}
|
||||
|
||||
$relationMapContainer.on("contextmenu", ".note-box", e => {
|
||||
const contextMenuItems = [
|
||||
const contextMenuItemsContainer = new ContextMenuItemsContainer([
|
||||
{title: "Remove note", cmd: "remove", uiIcon: "trash"},
|
||||
{title: "Edit title", cmd: "edit-title", uiIcon: "pencil"},
|
||||
];
|
||||
]);
|
||||
|
||||
contextMenuWidget.initContextMenu(e, contextMenuItems, noteContextMenuHandler);
|
||||
contextMenuWidget.initContextMenu(e, contextMenuItemsContainer, noteContextMenuHandler);
|
||||
|
||||
return false;
|
||||
});
|
||||
@@ -566,5 +576,6 @@ export default {
|
||||
getContent: () => JSON.stringify(mapData),
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup
|
||||
cleanup,
|
||||
scrollToTop: () => null
|
||||
}
|
||||
@@ -37,5 +37,6 @@ export default {
|
||||
getContent: () => "",
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup: () => $noteDetailRenderContent.empty()
|
||||
cleanup: () => $noteDetailRenderContent.empty(),
|
||||
scrollToTop: () => $component.scrollTop(0)
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
import noteDetailService from "./note_detail.js";
|
||||
import treeService from "./tree.js";
|
||||
import infoService from './info.js';
|
||||
|
||||
const $searchString = $("#search-string");
|
||||
const $component = $('#note-detail-search');
|
||||
const $refreshButton = $('#note-detail-search-refresh-results-button');
|
||||
|
||||
function getContent() {
|
||||
JSON.stringify({
|
||||
return JSON.stringify({
|
||||
searchString: $searchString.val()
|
||||
});
|
||||
}
|
||||
@@ -25,10 +28,19 @@ function show() {
|
||||
$searchString.on('input', noteDetailService.noteChanged);
|
||||
}
|
||||
|
||||
$refreshButton.click(async () => {
|
||||
await noteDetailService.saveNoteIfChanged();
|
||||
|
||||
treeService.reload();
|
||||
|
||||
infoService.showMessage('Tree has been refreshed.');
|
||||
});
|
||||
|
||||
export default {
|
||||
getContent,
|
||||
show,
|
||||
focus: () => null,
|
||||
onNoteChange: () => null,
|
||||
cleanup: () => null
|
||||
cleanup: () => null,
|
||||
scrollToTop: () => null
|
||||
}
|
||||
@@ -74,5 +74,6 @@ export default {
|
||||
if (textEditor) {
|
||||
textEditor.setData('');
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollToTop: () => $component.scrollTop(0)
|
||||
}
|
||||
@@ -3,64 +3,72 @@ import treeUtils from "./tree_utils.js";
|
||||
import linkService from "./link.js";
|
||||
import server from "./server.js";
|
||||
|
||||
function setupTooltip() {
|
||||
$(document).on("mouseenter", "a", async function() {
|
||||
const $link = $(this);
|
||||
|
||||
if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is to avoid showing tooltip from inside CKEditor link editor dialog
|
||||
if ($link.closest(".ck-link-actions").length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notePath = linkService.getNotePathFromUrl($link.attr("href"));
|
||||
|
||||
if (!notePath) {
|
||||
notePath = $link.attr("data-note-path");
|
||||
}
|
||||
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
||||
|
||||
const notePromise = noteDetailService.loadNote(noteId);
|
||||
const attributePromise = server.get('notes/' + noteId + '/attributes');
|
||||
|
||||
const [note, attributes] = await Promise.all([notePromise, attributePromise]);
|
||||
|
||||
const html = await renderTooltip(note, attributes);
|
||||
|
||||
// we need to check if we're still hovering over the element
|
||||
// since the operation to get tooltip content was async, it is possible that
|
||||
// we now create tooltip which won't close because it won't receive mouseleave event
|
||||
if ($(this).is(":hover")) {
|
||||
$(this).tooltip({
|
||||
delay: {"show": 300, "hide": 100},
|
||||
container: 'body',
|
||||
placement: 'auto',
|
||||
trigger: 'manual',
|
||||
boundary: 'window',
|
||||
title: html,
|
||||
html: true
|
||||
});
|
||||
|
||||
$(this).tooltip('show');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("mouseleave", "a", function() {
|
||||
$(this).tooltip('dispose');
|
||||
});
|
||||
function setupGlobalTooltip() {
|
||||
$(document).on("mouseenter", "a", mouseEnterHandler);
|
||||
$(document).on("mouseleave", "a", mouseLeaveHandler);
|
||||
|
||||
// close any tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
|
||||
$(document).on("click", () => $('.tooltip').remove());
|
||||
}
|
||||
|
||||
function setupElementTooltip($el) {
|
||||
$el.on('mouseenter', mouseEnterHandler);
|
||||
$el.on('mouseleave', mouseLeaveHandler);
|
||||
}
|
||||
|
||||
async function mouseEnterHandler() {
|
||||
const $link = $(this);
|
||||
|
||||
if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this is to avoid showing tooltip from inside CKEditor link editor dialog
|
||||
if ($link.closest(".ck-link-actions").length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let notePath = linkService.getNotePathFromUrl($link.attr("href"));
|
||||
|
||||
if (!notePath) {
|
||||
notePath = $link.attr("data-note-path");
|
||||
}
|
||||
|
||||
if (!notePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
||||
|
||||
const notePromise = noteDetailService.loadNote(noteId);
|
||||
const attributePromise = server.get('notes/' + noteId + '/attributes');
|
||||
|
||||
const [note, attributes] = await Promise.all([notePromise, attributePromise]);
|
||||
|
||||
const html = await renderTooltip(note, attributes);
|
||||
|
||||
// we need to check if we're still hovering over the element
|
||||
// since the operation to get tooltip content was async, it is possible that
|
||||
// we now create tooltip which won't close because it won't receive mouseleave event
|
||||
if ($(this).is(":hover")) {
|
||||
$(this).tooltip({
|
||||
delay: {"show": 300, "hide": 100},
|
||||
container: 'body',
|
||||
placement: 'auto',
|
||||
trigger: 'manual',
|
||||
boundary: 'window',
|
||||
title: html,
|
||||
html: true
|
||||
});
|
||||
|
||||
$(this).tooltip('show');
|
||||
}
|
||||
}
|
||||
|
||||
function mouseLeaveHandler() {
|
||||
$(this).tooltip('dispose');
|
||||
}
|
||||
|
||||
async function renderTooltip(note, attributes) {
|
||||
let content = '';
|
||||
const promoted = attributes.filter(attr =>
|
||||
@@ -103,7 +111,9 @@ async function renderTooltip(note, attributes) {
|
||||
}
|
||||
|
||||
if (note.type === 'text') {
|
||||
content += note.content;
|
||||
// surround with <div> for a case when note.content is pure text (e.g. "[protected]") which
|
||||
// then fails the jquery non-empty text test
|
||||
content += '<div>' + note.content + '</div>';
|
||||
}
|
||||
else if (note.type === 'code') {
|
||||
content += $("<pre>")
|
||||
@@ -125,5 +135,6 @@ async function renderTooltip(note, attributes) {
|
||||
}
|
||||
|
||||
export default {
|
||||
setupTooltip
|
||||
setupGlobalTooltip,
|
||||
setupElementTooltip
|
||||
}
|
||||
@@ -44,7 +44,7 @@ const DEFAULT_MIME_TYPES = [
|
||||
{ mime: 'text/x-yaml', title: 'YAML' }
|
||||
];
|
||||
|
||||
const noteTypeModel = new NoteTypeModel();
|
||||
let noteTypeModel;
|
||||
|
||||
function NoteTypeModel() {
|
||||
const self = this;
|
||||
@@ -153,7 +153,11 @@ function NoteTypeModel() {
|
||||
}
|
||||
}
|
||||
|
||||
ko.applyBindings(noteTypeModel, document.getElementById('note-type-wrapper'));
|
||||
function init() {
|
||||
noteTypeModel = new NoteTypeModel();
|
||||
|
||||
ko.applyBindings(noteTypeModel, document.getElementById('note-type-wrapper'));
|
||||
}
|
||||
|
||||
export default {
|
||||
getNoteType: () => noteTypeModel.type(),
|
||||
@@ -168,5 +172,6 @@ export default {
|
||||
|
||||
getDefaultCodeMimeTypes: () => DEFAULT_MIME_TYPES.slice(),
|
||||
getCodeMimeTypes: () => noteTypeModel.codeMimeTypes(),
|
||||
setCodeMimeTypes: types => noteTypeModel.codeMimeTypes(types)
|
||||
setCodeMimeTypes: types => noteTypeModel.codeMimeTypes(types),
|
||||
init
|
||||
};
|
||||
@@ -6,13 +6,16 @@ import protectedSessionHolder from './protected_session_holder.js';
|
||||
import infoService from "./info.js";
|
||||
|
||||
const $dialog = $("#protected-session-password-dialog");
|
||||
const $passwordForm = $("#protected-session-password-form");
|
||||
const $password = $("#protected-session-password");
|
||||
const $component = $("#protected-session-password-component");
|
||||
const $passwordForms = $(".protected-session-password-form");
|
||||
const $passwordInputs = $(".protected-session-password");
|
||||
const $passwordInModal = $("#protected-session-password-in-modal");
|
||||
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");
|
||||
const $noteTitle = $("#note-title");
|
||||
|
||||
let protectedSessionDeferred = null;
|
||||
|
||||
@@ -36,12 +39,19 @@ function ensureProtectedSession(requireProtectedSession, modal) {
|
||||
// using deferred instead of promise because it allows resolving from outside
|
||||
protectedSessionDeferred = dfd;
|
||||
|
||||
if (treeService.getCurrentNode().data.isProtected) {
|
||||
$noteDetailWrapper.hide();
|
||||
}
|
||||
// user shouldn't be able to edit note title
|
||||
$noteTitle.prop("readonly", true);
|
||||
|
||||
$dialog.toggleClass("modalless", !modal);
|
||||
$dialog.modal();
|
||||
if (modal) {
|
||||
if (treeService.getCurrentNode().data.isProtected) {
|
||||
$noteDetailWrapper.hide();
|
||||
}
|
||||
|
||||
$dialog.modal();
|
||||
}
|
||||
else {
|
||||
$component.show();
|
||||
}
|
||||
}
|
||||
else {
|
||||
dfd.resolve(false);
|
||||
@@ -50,14 +60,13 @@ function ensureProtectedSession(requireProtectedSession, modal) {
|
||||
return dfd.promise();
|
||||
}
|
||||
|
||||
async function setupProtectedSession() {
|
||||
const password = $password.val();
|
||||
$password.val("");
|
||||
async function setupProtectedSession(password) {
|
||||
$passwordInputs.val("");
|
||||
|
||||
const response = await enterProtectedSessionOnServer(password);
|
||||
|
||||
if (!response.success) {
|
||||
infoService.showError("Wrong password.");
|
||||
infoService.showError("Wrong password.", 3000);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -65,20 +74,22 @@ async function setupProtectedSession() {
|
||||
|
||||
$dialog.modal("hide");
|
||||
|
||||
await 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();
|
||||
|
||||
treeService.reload();
|
||||
|
||||
if (protectedSessionDeferred !== null) {
|
||||
ensureDialogIsClosed($dialog, $password);
|
||||
ensureDialogIsClosed();
|
||||
|
||||
$noteDetailWrapper.show();
|
||||
|
||||
protectedSessionDeferred.resolve(true);
|
||||
protectedSessionDeferred = null;
|
||||
|
||||
$protectedSessionOnButton.addClass('active');
|
||||
$protectedSessionOffButton.removeClass('active');
|
||||
$enterProtectedSessionButton.hide();
|
||||
$leaveProtectedSessionButton.show();
|
||||
}
|
||||
|
||||
infoService.showMessage("Protected session has been started.");
|
||||
@@ -91,7 +102,7 @@ function ensureDialogIsClosed() {
|
||||
}
|
||||
catch (e) {}
|
||||
|
||||
$password.val('');
|
||||
$passwordInputs.val('');
|
||||
}
|
||||
|
||||
async function enterProtectedSessionOnServer(password) {
|
||||
@@ -114,7 +125,7 @@ async function protectNoteAndSendToServer() {
|
||||
|
||||
treeService.setProtected(note.noteId, note.isProtected);
|
||||
|
||||
noteDetailService.setNoteBackgroundIfProtected(note);console.log(note);
|
||||
noteDetailService.setNoteBackgroundIfProtected(note);
|
||||
}
|
||||
|
||||
async function unprotectNoteAndSendToServer() {
|
||||
@@ -155,32 +166,24 @@ async function protectSubtree(noteId, protect) {
|
||||
noteDetailService.reload();
|
||||
}
|
||||
|
||||
$passwordForm.submit(() => {
|
||||
setupProtectedSession();
|
||||
$passwordForms.submit(function() { // needs to stay as function
|
||||
const password = $(this).find(".protected-session-password").val();
|
||||
|
||||
setupProtectedSession(password);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// this doesn't work, event is not triggered :/
|
||||
$dialog.on("show.bs.modal", e => function() {
|
||||
if ($(this).hasClass("modalless")) {
|
||||
// return "stolen" focus to tree
|
||||
treeService.getCurrentNode().setFocus();
|
||||
}
|
||||
else {
|
||||
$password.focus();
|
||||
}
|
||||
});
|
||||
|
||||
$protectButton.click(protectNoteAndSendToServer);
|
||||
$unprotectButton.click(unprotectNoteAndSendToServer);
|
||||
|
||||
$dialog.on("shown.bs.modal", e => $password.focus());
|
||||
$dialog.on("shown.bs.modal", e => $passwordInModal.focus());
|
||||
|
||||
export default {
|
||||
ensureProtectedSession,
|
||||
protectSubtree,
|
||||
ensureDialogIsClosed,
|
||||
enterProtectedSession,
|
||||
leaveProtectedSession
|
||||
leaveProtectedSession,
|
||||
protectNoteAndSendToServer
|
||||
};
|
||||
@@ -1,9 +1,13 @@
|
||||
import FrontendScriptApi from './frontend_script_api.js';
|
||||
import utils from './utils.js';
|
||||
import treeCache from './tree_cache.js';
|
||||
|
||||
function ScriptContext(startNote, allNotes, originEntity = null) {
|
||||
async function ScriptContext(startNoteId, allNoteIds, originEntity = null) {
|
||||
const modules = {};
|
||||
|
||||
const startNote = await treeCache.getNote(startNoteId);
|
||||
const allNotes = await treeCache.getNotes(allNoteIds);
|
||||
|
||||
return {
|
||||
modules: modules,
|
||||
notes: utils.toObject(allNotes, note => [note.noteId, note]),
|
||||
|
||||
@@ -87,7 +87,7 @@ $searchInput.keyup(e => {
|
||||
if (e && e.which === $.ui.keyCode.ENTER) {
|
||||
doSearch();
|
||||
}
|
||||
}).focus();
|
||||
});
|
||||
|
||||
$doSearchButton.click(() => doSearch()); // keep long form because of argument
|
||||
$resetSearchButton.click(resetSearch);
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import treeBuilder from "./tree_builder.js";
|
||||
import treeKeyBindings from "./tree_keybindings.js";
|
||||
import Branch from '../entities/branch.js';
|
||||
import NoteShort from '../entities/note_short.js';
|
||||
import hoistedNoteService from '../services/hoisted_note.js';
|
||||
import confirmDialog from "../dialogs/confirm.js";
|
||||
|
||||
const $tree = $("#tree");
|
||||
const $createTopLevelNoteButton = $("#create-top-level-note-button");
|
||||
@@ -81,6 +83,10 @@ async function setNodeTitleWithPrefix(node) {
|
||||
node.setTitle(utils.escapeHtml(title));
|
||||
}
|
||||
|
||||
function getNode(childNoteId, parentNoteId) {
|
||||
return getNodesByNoteId(childNoteId).find(node => !parentNoteId || node.data.parentNoteId === parentNoteId);
|
||||
}
|
||||
|
||||
async function expandToNote(notePath, expandOpts) {
|
||||
utils.assertArguments(notePath);
|
||||
|
||||
@@ -88,37 +94,72 @@ async function expandToNote(notePath, expandOpts) {
|
||||
|
||||
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
||||
|
||||
let parentNoteId = 'none';
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
let hoistedNoteFound = false;
|
||||
|
||||
let parentNoteId = null;
|
||||
|
||||
for (const childNoteId of runPath) {
|
||||
const node = getNodesByNoteId(childNoteId).find(node => node.data.parentNoteId === parentNoteId);
|
||||
|
||||
if (!node) {
|
||||
console.error(`Can't find node for noteId=${childNoteId} with parentNoteId=${parentNoteId}`);
|
||||
if (childNoteId === hoistedNoteId) {
|
||||
hoistedNoteFound = true;
|
||||
}
|
||||
|
||||
if (childNoteId === noteId) {
|
||||
return node;
|
||||
}
|
||||
else {
|
||||
await node.setExpanded(true, expandOpts);
|
||||
// we expand only after hoisted note since before then nodes are not actually present in the tree
|
||||
if (hoistedNoteFound) {
|
||||
// for first node (!parentNoteId) it doesn't matter which node is found
|
||||
let node = getNode(childNoteId, parentNoteId);
|
||||
|
||||
if (!node && parentNoteId) {
|
||||
const parents = getNodesByNoteId(parentNoteId);
|
||||
|
||||
for (const parent of parents) {
|
||||
// force load parents. This is useful when fancytree doesn't contain recently created notes yet.
|
||||
await parent.load(true);
|
||||
}
|
||||
|
||||
node = getNode(childNoteId, parentNoteId);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
console.error(`Can't find node for noteId=${childNoteId} with parentNoteId=${parentNoteId}`);
|
||||
}
|
||||
|
||||
if (childNoteId === noteId) {
|
||||
return node;
|
||||
} else {
|
||||
await node.setExpanded(true, expandOpts);
|
||||
}
|
||||
}
|
||||
|
||||
parentNoteId = childNoteId;
|
||||
}
|
||||
}
|
||||
|
||||
async function activateNote(notePath, newNote) {
|
||||
async function activateNote(notePath, noteLoadedListener) {
|
||||
utils.assertArguments(notePath);
|
||||
|
||||
// notePath argument can contain only noteId which is not good when hoisted since
|
||||
// then we need to check the whole note path
|
||||
const runNotePath = await getRunPath(notePath);
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
if (hoistedNoteId !== 'root' && !runNotePath.includes(hoistedNoteId)) {
|
||||
if (!await confirmDialog.confirm("Requested note is outside of hoisted note subtree. Do you want to unhoist?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unhoist so we can activate the note
|
||||
await hoistedNoteService.unhoist();
|
||||
}
|
||||
|
||||
if (glob.activeDialog) {
|
||||
glob.activeDialog.modal('hide');
|
||||
}
|
||||
|
||||
const node = await expandToNote(notePath);
|
||||
|
||||
if (newNote) {
|
||||
noteDetailService.newNoteCreated();
|
||||
if (noteLoadedListener) {
|
||||
noteDetailService.addDetailLoadedListener(node.data.noteId, noteLoadedListener);
|
||||
}
|
||||
|
||||
// we use noFocus because when we reload the tree because of background changes
|
||||
@@ -143,6 +184,8 @@ async function getRunPath(notePath) {
|
||||
path.push('root');
|
||||
}
|
||||
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const effectivePath = [];
|
||||
let childNoteId = null;
|
||||
let i = 0;
|
||||
@@ -195,13 +238,12 @@ async function getRunPath(notePath) {
|
||||
}
|
||||
}
|
||||
|
||||
if (parentNoteId === 'none') {
|
||||
effectivePath.push(parentNoteId);
|
||||
childNoteId = parentNoteId;
|
||||
|
||||
if (parentNoteId === hoistedNoteId) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
effectivePath.push(parentNoteId);
|
||||
childNoteId = parentNoteId;
|
||||
}
|
||||
}
|
||||
|
||||
return effectivePath.reverse();
|
||||
@@ -322,6 +364,11 @@ function clearSelectedNodes() {
|
||||
}
|
||||
|
||||
async function treeInitialized() {
|
||||
// - is used in mobile to indicate that we don't want to activate any note after load
|
||||
if (startNotePath === '-') {
|
||||
return;
|
||||
}
|
||||
|
||||
const noteId = treeUtils.getNoteIdFromNotePath(startNotePath);
|
||||
|
||||
if (!await treeCache.getNote(noteId)) {
|
||||
@@ -344,7 +391,7 @@ function initFancyTree(tree) {
|
||||
$tree.fancytree({
|
||||
autoScroll: true,
|
||||
keyboard: false, // we takover keyboard handling in the hotkeys plugin
|
||||
extensions: ["hotkeys", "filter", "dnd5", "clones"],
|
||||
extensions: ["hotkeys", "dnd5", "clones"],
|
||||
source: tree,
|
||||
scrollParent: $tree,
|
||||
minExpandLevel: 2, // root can't be collapsed
|
||||
@@ -382,18 +429,6 @@ function initFancyTree(tree) {
|
||||
hotkeys: {
|
||||
keydown: treeKeyBindings
|
||||
},
|
||||
filter: {
|
||||
autoApply: true, // Re-apply last filter if lazy data is loaded
|
||||
autoExpand: true, // Expand all branches that contain matches while filtered
|
||||
counter: false, // Show a badge with number of matching child nodes near parent icons
|
||||
fuzzy: false, // Match single characters in order, e.g. 'fb' will match 'FooBar'
|
||||
hideExpandedCounter: true, // Hide counter badge if parent is expanded
|
||||
hideExpanders: false, // Hide expanders if all child nodes are hidden by filter
|
||||
highlight: true, // Highlight matches by wrapping inside <mark> tags
|
||||
leavesOnly: false, // Match end nodes only
|
||||
nodata: true, // Display a 'no data' status node if result is empty
|
||||
mode: "hide" // Grayout unmatched nodes (pass "hide" to remove unmatched node instead)
|
||||
},
|
||||
dnd5: dragAndDropSetup,
|
||||
lazyLoad: function(event, data) {
|
||||
const noteId = data.node.data.noteId;
|
||||
@@ -402,12 +437,35 @@ function initFancyTree(tree) {
|
||||
},
|
||||
clones: {
|
||||
highlightActiveClones: true
|
||||
},
|
||||
enhanceTitle: async function (event, data) {
|
||||
const node = data.node;
|
||||
const $span = $(node.span);
|
||||
|
||||
if (node.data.noteId !== 'root'
|
||||
&& node.data.noteId === await hoistedNoteService.getHoistedNoteId()
|
||||
&& $span.find('.unhoist-button').length === 0) {
|
||||
|
||||
const unhoistButton = $('<span> (<a class="unhoist-button">unhoist</a>)</span>');
|
||||
|
||||
$span.append(unhoistButton);
|
||||
}
|
||||
},
|
||||
// this is done to automatically lazy load all expanded search notes after tree load
|
||||
loadChildren: function(event, data) {
|
||||
data.node.visit(function(subNode){
|
||||
// Load all lazy/unloaded child nodes
|
||||
// (which will trigger `loadChildren` recursively)
|
||||
if( subNode.isUndefined() && subNode.isExpanded() ) {
|
||||
subNode.load();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$tree.on('contextmenu', '.fancytree-node', function(e) {
|
||||
treeContextMenuService.getContextMenuItems(e).then(contextMenuItems => {
|
||||
contextMenuWidget.initContextMenu(e, contextMenuItems, treeContextMenuService.selectContextMenuItem);
|
||||
treeContextMenuService.getContextMenuItems(e).then(contextMenuItemContainer => {
|
||||
contextMenuWidget.initContextMenu(e, contextMenuItemContainer, treeContextMenuService.selectContextMenuItem);
|
||||
});
|
||||
|
||||
return false; // blocks default browser right click menu
|
||||
@@ -440,9 +498,11 @@ async function loadTree() {
|
||||
return await treeBuilder.prepareTree(resp.notes, resp.branches, resp.relations);
|
||||
}
|
||||
|
||||
function collapseTree(node = null) {
|
||||
async function collapseTree(node = null) {
|
||||
if (!node) {
|
||||
node = $tree.fancytree("getRootNode");
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
node = getNodesByNoteId(hoistedNoteId)[0];
|
||||
}
|
||||
|
||||
node.setExpanded(false);
|
||||
@@ -483,9 +543,11 @@ async function setNoteTitle(noteId, title) {
|
||||
}
|
||||
|
||||
async function createNewTopLevelNote() {
|
||||
const rootNode = getNodesByNoteId('root')[0];
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
await createNote(rootNode, "root", "into", false);
|
||||
const rootNode = getNodesByNoteId(hoistedNoteId)[0];
|
||||
|
||||
await createNote(rootNode, hoistedNoteId, "into", false);
|
||||
}
|
||||
|
||||
async function createNote(node, parentNoteId, target, isProtected, saveSelection = false) {
|
||||
@@ -500,6 +562,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;
|
||||
|
||||
@@ -524,7 +592,7 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
|
||||
|
||||
await noteDetailService.saveNoteIfChanged();
|
||||
|
||||
noteDetailService.newNoteCreated();
|
||||
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusAndSelectTitle);
|
||||
|
||||
const noteEntity = new NoteShort(treeCache, note);
|
||||
const branchEntity = new Branch(treeCache, branch);
|
||||
@@ -539,7 +607,7 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
|
||||
branchId: branchEntity.branchId,
|
||||
isProtected: isProtected,
|
||||
extraClasses: await treeBuilder.getExtraClasses(noteEntity),
|
||||
icon: treeBuilder.getIcon(noteEntity)
|
||||
icon: await treeBuilder.getIcon(noteEntity)
|
||||
};
|
||||
|
||||
if (target === 'after') {
|
||||
@@ -555,7 +623,10 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
|
||||
|
||||
await node.getLastChild().setActive(true);
|
||||
|
||||
const parentNoteEntity = await treeCache.getNote(node.data.noteId);
|
||||
|
||||
node.folder = true;
|
||||
node.icon = await treeBuilder.getIcon(parentNoteEntity); // icon might change into folder
|
||||
node.renderTitle();
|
||||
}
|
||||
else {
|
||||
@@ -564,8 +635,6 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
|
||||
|
||||
clearSelectedNodes(); // to unmark previously active node
|
||||
|
||||
infoService.showMessage("Created!");
|
||||
|
||||
return {note, branch};
|
||||
}
|
||||
|
||||
@@ -613,11 +682,15 @@ messagingService.subscribeToSyncMessages(syncData => {
|
||||
}
|
||||
});
|
||||
|
||||
utils.bindShortcut('ctrl+o', () => {
|
||||
utils.bindShortcut('ctrl+o', async () => {
|
||||
const node = getCurrentNode();
|
||||
const parentNoteId = node.data.parentNoteId;
|
||||
const isProtected = treeUtils.getParentProtectedStatus(node);
|
||||
|
||||
if (node.data.noteId === 'root' || node.data.noteId === await hoistedNoteService.getHoistedNoteId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
createNote(node, parentNoteId, 'after', isProtected, true);
|
||||
});
|
||||
|
||||
@@ -636,7 +709,7 @@ utils.bindShortcut('ctrl+.', scrollToCurrentNote);
|
||||
$(window).bind('hashchange', function() {
|
||||
const notePath = getNotePathFromAddress();
|
||||
|
||||
if (getCurrentNotePath() !== notePath) {
|
||||
if (notePath !== '-' && getCurrentNotePath() !== notePath) {
|
||||
console.debug("Switching to " + notePath + " because of hash change");
|
||||
|
||||
activateNote(notePath);
|
||||
@@ -665,8 +738,12 @@ export default {
|
||||
setPrefix,
|
||||
createNewTopLevelNote,
|
||||
createNote,
|
||||
createNoteInto,
|
||||
getSelectedNodes,
|
||||
clearSelectedNodes,
|
||||
sortAlphabetically,
|
||||
showTree
|
||||
showTree,
|
||||
loadTree,
|
||||
treeInitialized,
|
||||
setExpandedToServer
|
||||
};
|
||||
@@ -4,13 +4,26 @@ import Branch from "../entities/branch.js";
|
||||
import server from "./server.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
import messagingService from "./messaging.js";
|
||||
import hoistedNoteService from "./hoisted_note.js";
|
||||
|
||||
async function prepareTree(noteRows, branchRows, relations) {
|
||||
utils.assertArguments(noteRows, branchRows, relations);
|
||||
|
||||
treeCache.load(noteRows, branchRows, relations);
|
||||
|
||||
return [ await prepareNode(await treeCache.getBranch('root')) ];
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
let hoistedBranch;
|
||||
|
||||
if (hoistedNoteId === 'root') {
|
||||
hoistedBranch = await treeCache.getBranch('root');
|
||||
}
|
||||
else {
|
||||
const hoistedNote = await treeCache.getNote(hoistedNoteId);
|
||||
hoistedBranch = (await hoistedNote.getBranches())[0];
|
||||
}
|
||||
|
||||
return [ await prepareNode(hoistedBranch) ];
|
||||
}
|
||||
|
||||
async function prepareBranch(note) {
|
||||
@@ -22,10 +35,15 @@ async function prepareBranch(note) {
|
||||
}
|
||||
}
|
||||
|
||||
function getIcon(note) {
|
||||
async function getIcon(note) {
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
if (note.noteId === 'root') {
|
||||
return "jam jam-chevrons-right";
|
||||
}
|
||||
else if (note.noteId === hoistedNoteId) {
|
||||
return "jam jam-arrow-up";
|
||||
}
|
||||
else if (note.type === 'text') {
|
||||
if (note.hasChildren()) {
|
||||
return "jam jam-folder";
|
||||
@@ -57,6 +75,7 @@ function getIcon(note) {
|
||||
async function prepareNode(branch) {
|
||||
const note = await branch.getNote();
|
||||
const title = (branch.prefix ? (branch.prefix + " - ") : "") + note.title;
|
||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const node = {
|
||||
noteId: note.noteId,
|
||||
@@ -65,9 +84,9 @@ async function prepareNode(branch) {
|
||||
isProtected: note.isProtected,
|
||||
title: utils.escapeHtml(title),
|
||||
extraClasses: await getExtraClasses(note),
|
||||
icon: getIcon(note),
|
||||
icon: await getIcon(note),
|
||||
refKey: note.noteId,
|
||||
expanded: note.type !== 'search' && branch.isExpanded
|
||||
expanded: branch.isExpanded || hoistedNoteId === note.noteId
|
||||
};
|
||||
|
||||
if (note.hasChildren() || note.type === 'search') {
|
||||
@@ -135,10 +154,6 @@ async function getExtraClasses(note) {
|
||||
|
||||
const extraClasses = [];
|
||||
|
||||
if (note.noteId === 'root') {
|
||||
extraClasses.push("tree-root");
|
||||
}
|
||||
|
||||
if (note.isProtected) {
|
||||
extraClasses.push("protected");
|
||||
}
|
||||
@@ -153,9 +168,24 @@ async function getExtraClasses(note) {
|
||||
|
||||
extraClasses.push(note.type);
|
||||
|
||||
if (note.mime) { // some notes should not have mime type (e.g. render)
|
||||
extraClasses.push(getMimeTypeClass(note.mime));
|
||||
}
|
||||
|
||||
return extraClasses.join(" ");
|
||||
}
|
||||
|
||||
function getMimeTypeClass(mime) {
|
||||
const semicolonIdx = mime.indexOf(';');
|
||||
|
||||
if (semicolonIdx !== -1) {
|
||||
// stripping everything following the semicolon
|
||||
mime = mime.substr(0, semicolonIdx);
|
||||
}
|
||||
|
||||
return 'mime-' + mime.toLowerCase().replace(/[\W_]+/g,"-");
|
||||
}
|
||||
|
||||
export default {
|
||||
prepareTree,
|
||||
prepareBranch,
|
||||
|
||||
@@ -158,7 +158,11 @@ class TreeCache {
|
||||
return;
|
||||
}
|
||||
|
||||
treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId];
|
||||
const branchId = treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId];
|
||||
const branch = await this.getBranch(branchId);
|
||||
branch.parentNoteId = newParentNoteId;
|
||||
|
||||
treeCache.childParentToBranch[childNoteId + '-' + newParentNoteId] = branchId;
|
||||
delete treeCache.childParentToBranch[childNoteId + '-' + oldParentNoteId]; // this is correct because we know that oldParentId isn't same as newParentId
|
||||
|
||||
// remove old associations
|
||||
|
||||
@@ -6,13 +6,12 @@ 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";
|
||||
import contextMenuService from "./context_menu.js";
|
||||
|
||||
const $tree = $("#tree");
|
||||
import hoistedNoteService from './hoisted_note.js';
|
||||
import ContextMenuItemsContainer from './context_menu_items_container.js';
|
||||
|
||||
let clipboardIds = [];
|
||||
let clipboardMode = null;
|
||||
@@ -79,10 +78,12 @@ function cut(nodes) {
|
||||
}
|
||||
|
||||
const contextMenuItems = [
|
||||
{title: "Insert note here <kbd>Ctrl+O</kbd>", cmd: "insertNoteHere", uiIcon: "plus"},
|
||||
{title: "Insert note after <kbd>Ctrl+O</kbd>", cmd: "insertNoteAfter", uiIcon: "plus"},
|
||||
{title: "Insert child note <kbd>Ctrl+P</kbd>", cmd: "insertChildNote", uiIcon: "plus"},
|
||||
{title: "Delete", cmd: "delete", uiIcon: "trash"},
|
||||
{title: "Delete <kbd>Delete</kbd>", cmd: "delete", uiIcon: "trash"},
|
||||
{title: "----"},
|
||||
{title: "Hoist note <kbd>Ctrl-H</kbd>", cmd: "hoist", uiIcon: "arrow-up"},
|
||||
{title: "Unhoist note <kbd>Ctrl-H</kbd>", cmd: "unhoist", uiIcon: "arrow-up"},
|
||||
{title: "Edit branch prefix <kbd>F2</kbd>", cmd: "editBranchPrefix", uiIcon: "pencil"},
|
||||
{title: "----"},
|
||||
{title: "Protect subtree", cmd: "protectSubtree", uiIcon: "shield-check"},
|
||||
@@ -93,7 +94,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"},
|
||||
@@ -101,34 +102,30 @@ const contextMenuItems = [
|
||||
{title: "Sort alphabetically <kbd>Alt+S</kbd>", cmd: "sortAlphabetically", uiIcon: "arrows-v"}
|
||||
];
|
||||
|
||||
function enableItem(cmd, enabled) {
|
||||
const item = contextMenuItems.find(item => item.cmd === cmd);
|
||||
|
||||
if (!item) {
|
||||
throw new Error(`Command ${cmd} has not been found!`);
|
||||
}
|
||||
|
||||
item.enabled = enabled;
|
||||
}
|
||||
|
||||
async function getContextMenuItems(event) {
|
||||
const node = $.ui.fancytree.getNode(event);
|
||||
const branch = await treeCache.getBranch(node.data.branchId);
|
||||
const note = await treeCache.getNote(node.data.noteId);
|
||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||
const isNotRoot = note.noteId !== 'root';
|
||||
const isHoisted = note.noteId === await hoistedNoteService.getHoistedNoteId();
|
||||
|
||||
const itemsContainer = new ContextMenuItemsContainer(contextMenuItems);
|
||||
|
||||
// Modify menu entries depending on node status
|
||||
enableItem("insertNoteHere", isNotRoot && parentNote.type !== 'search');
|
||||
enableItem("insertChildNote", note.type !== 'search');
|
||||
enableItem("delete", isNotRoot && parentNote.type !== 'search');
|
||||
enableItem("copy", isNotRoot);
|
||||
enableItem("cut", isNotRoot);
|
||||
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("editBranchPrefix", isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("insertNoteAfter", isNotRoot && !isHoisted && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("insertChildNote", note.type !== 'search');
|
||||
itemsContainer.enableItem("delete", isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("copy", isNotRoot);
|
||||
itemsContainer.enableItem("cut", isNotRoot);
|
||||
itemsContainer.enableItem("pasteAfter", clipboardIds.length > 0 && isNotRoot && parentNote.type !== 'search');
|
||||
itemsContainer.enableItem("pasteInto", clipboardIds.length > 0 && note.type !== 'search');
|
||||
itemsContainer.enableItem("importIntoNote", note.type !== 'search');
|
||||
itemsContainer.enableItem("export", note.type !== 'search');
|
||||
itemsContainer.enableItem("editBranchPrefix", isNotRoot && parentNote.type !== 'search');
|
||||
|
||||
itemsContainer.hideItem("hoist", isHoisted);
|
||||
itemsContainer.hideItem("unhoist", !isHoisted || !isNotRoot);
|
||||
|
||||
// Activate node on right-click
|
||||
node.setActive();
|
||||
@@ -139,14 +136,14 @@ async function getContextMenuItems(event) {
|
||||
node.setSelected(true);
|
||||
treeService.clearSelectedNodes();
|
||||
|
||||
return contextMenuItems;
|
||||
return itemsContainer;
|
||||
}
|
||||
|
||||
function selectContextMenuItem(event, cmd) {
|
||||
// context menu is always triggered on current node
|
||||
const node = treeService.getCurrentNode();
|
||||
|
||||
if (cmd === "insertNoteHere") {
|
||||
if (cmd === "insertNoteAfter") {
|
||||
const parentNoteId = node.data.parentNoteId;
|
||||
const isProtected = treeUtils.getParentProtectedStatus(node);
|
||||
|
||||
@@ -179,8 +176,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);
|
||||
@@ -194,6 +191,12 @@ function selectContextMenuItem(event, cmd) {
|
||||
else if (cmd === "sortAlphabetically") {
|
||||
treeService.sortAlphabetically(node.data.noteId);
|
||||
}
|
||||
else if (cmd === "hoist") {
|
||||
hoistedNoteService.setHoistedNoteId(node.data.noteId);
|
||||
}
|
||||
else if (cmd === "unhoist") {
|
||||
hoistedNoteService.unhoist();
|
||||
}
|
||||
else {
|
||||
messagingService.logError("Unknown command: " + cmd);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import treeChangesService from "./branches.js";
|
||||
import contextMenuService from "./tree_context_menu.js";
|
||||
import treeService from "./tree.js";
|
||||
import editBranchPrefixDialog from "../dialogs/branch_prefix.js";
|
||||
import hoistedNoteService from "./hoisted_note.js";
|
||||
|
||||
const keyBindings = {
|
||||
"del": node => {
|
||||
@@ -113,6 +114,18 @@ const keyBindings = {
|
||||
node.getParent().setActive().then(treeService.clearSelectedNodes);
|
||||
}
|
||||
},
|
||||
"ctrl+h": node => {
|
||||
hoistedNoteService.getHoistedNoteId().then(hoistedNoteId => {
|
||||
if (node.data.noteId === hoistedNoteId) {
|
||||
hoistedNoteService.unhoist();
|
||||
}
|
||||
else {
|
||||
hoistedNoteService.setHoistedNoteId(node.data.noteId);
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
// code below shouldn't be necessary normally, however there's some problem with interaction with context menu plugin
|
||||
// after opening context menu, standard shortcuts don't work, but they are detected here
|
||||
// so we essentially takeover the standard handling with our implementation.
|
||||
|
||||
@@ -23,6 +23,7 @@ function formatTimeWithSeconds(date) {
|
||||
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds());
|
||||
}
|
||||
|
||||
// this is producing local time!
|
||||
function formatDate(date) {
|
||||
// return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
|
||||
// instead of european format we'll just use ISO as that's pretty unambiguous
|
||||
@@ -30,6 +31,7 @@ function formatDate(date) {
|
||||
return formatDateISO(date);
|
||||
}
|
||||
|
||||
// this is producing local time!
|
||||
function formatDateISO(date) {
|
||||
return date.getFullYear() + "-" + padNum(date.getMonth() + 1) + "-" + padNum(date.getDate());
|
||||
}
|
||||
@@ -46,6 +48,10 @@ function isElectron() {
|
||||
return window && window.process && window.process.type;
|
||||
}
|
||||
|
||||
function isMac() {
|
||||
return navigator.platform.indexOf('Mac') > -1;
|
||||
}
|
||||
|
||||
function assertArguments() {
|
||||
for (const i in arguments) {
|
||||
if (!arguments[i]) {
|
||||
@@ -132,11 +138,38 @@ function randomString(len) {
|
||||
}
|
||||
|
||||
function bindShortcut(keyboardShortcut, handler) {
|
||||
$(document).bind('keydown', keyboardShortcut, e => {
|
||||
handler();
|
||||
if (isDesktop()) {
|
||||
if (isMac()) {
|
||||
// use CMD (meta) instead of CTRL for all shortcuts
|
||||
keyboardShortcut = keyboardShortcut.replace("ctrl", "meta");
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
$(document).bind('keydown', keyboardShortcut, e => {
|
||||
console.log(e);
|
||||
handler();
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isMobile() {
|
||||
return window.device === "mobile"
|
||||
// window.device is not available in setup
|
||||
|| (!window.device && /Mobi/.test(navigator.userAgent));
|
||||
}
|
||||
|
||||
function isDesktop() {
|
||||
return window.device === "desktop"
|
||||
// window.device is not available in setup
|
||||
|| (!window.device && !/Mobi/.test(navigator.userAgent));
|
||||
}
|
||||
|
||||
function setCookie(name, value) {
|
||||
const date = new Date(Date.now() + 10 * 365 * 24 * 60 * 60 * 1000);
|
||||
const expires = "; expires=" + date.toUTCString();
|
||||
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -150,6 +183,7 @@ export default {
|
||||
formatDateTime,
|
||||
now,
|
||||
isElectron,
|
||||
isMac,
|
||||
assertArguments,
|
||||
isTopLevelNode,
|
||||
isRootNode,
|
||||
@@ -161,5 +195,8 @@ export default {
|
||||
download,
|
||||
toObject,
|
||||
randomString,
|
||||
bindShortcut
|
||||
bindShortcut,
|
||||
isMobile,
|
||||
isDesktop,
|
||||
setCookie
|
||||
};
|
||||
@@ -1,4 +1,7 @@
|
||||
import utils from "./services/utils.js";
|
||||
import macInit from './services/mac_init.js';
|
||||
|
||||
macInit.init();
|
||||
|
||||
function SetupModel() {
|
||||
if (syncInProgress) {
|
||||
@@ -25,26 +28,20 @@ function SetupModel() {
|
||||
|
||||
this.instanceType = utils.isElectron() ? "desktop" : "server";
|
||||
|
||||
this.setupTypeSelected = this.getSetupType = () =>
|
||||
this.setupNewDocument()
|
||||
|| this.setupSyncFromDesktop()
|
||||
|| this.setupSyncFromServer();
|
||||
this.setupTypeSelected = () => !!this.setupType();
|
||||
|
||||
this.selectSetupType = () => {
|
||||
this.step(this.getSetupType());
|
||||
this.setupType(this.getSetupType());
|
||||
this.step(this.setupType());
|
||||
};
|
||||
|
||||
this.back = () => {
|
||||
this.step("setup-type");
|
||||
|
||||
this.setupNewDocument(false);
|
||||
this.setupSyncFromServer(false);
|
||||
this.setupSyncFromDesktop(false);
|
||||
this.setupType("");
|
||||
};
|
||||
|
||||
this.finish = async () => {
|
||||
if (this.setupNewDocument()) {
|
||||
if (this.setupType() === 'new-document') {
|
||||
const username = this.username();
|
||||
const password1 = this.password1();
|
||||
const password2 = this.password2();
|
||||
@@ -72,7 +69,7 @@ function SetupModel() {
|
||||
window.location.replace("/");
|
||||
});
|
||||
}
|
||||
else if (this.setupSyncFromServer()) {
|
||||
else if (this.setupType() === 'sync-from-server') {
|
||||
const syncServerHost = this.syncServerHost();
|
||||
const syncProxy = this.syncProxy();
|
||||
const username = this.username();
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user