Compare commits

..

43 Commits

Author SHA1 Message Date
zadam
fda219d070 release 0.36.0-beta 2019-10-15 20:42:17 +02:00
zadam
2be1aca2f3 build fixes 2019-10-15 20:32:43 +02:00
zadam
1b318d6a30 fix tab cleanup 2019-10-15 19:42:39 +02:00
zadam
22c4859d42 grey out archived items in the tree 2019-10-15 19:16:44 +02:00
zadam
80a6361cf1 update to demo db 2019-10-14 12:11:27 +02:00
zadam
8439effeeb Merge remote-tracking branch 'origin/master' into master2 2019-10-14 12:06:18 +02:00
zadam
fafab95a07 auto-book has variable number of columns based on the right pane width 2019-10-14 12:06:10 +02:00
Johannes Wünsch
24c8e8fc2b fix gitpod (#658) 2019-10-14 11:55:12 +02:00
zadam
1923bf7dda added some basic book examples to demo document 2019-10-14 11:15:38 +02:00
zadam
2ee94a3a69 changed import progress notification so it shows up for drag & drop as well 2019-10-14 10:31:58 +02:00
zadam
2fb3a3eff9 force note sync will sync also note content 2019-10-11 21:24:49 +02:00
zadam
bcbbf4dc3e improvements to build process 2019-10-11 21:22:59 +02:00
zadam
7dc793920f fix spellcheck build on windows 2019-10-10 23:24:25 +02:00
zadam
0b43eceb2d Merge branch 'stable'
# Conflicts:
#	package-lock.json
#	package.json
2019-10-10 21:26:57 +02:00
zadam
85f736139b fix opening note revisions from the sidebar 2019-10-10 20:00:06 +02:00
zadam
98a6670cb4 prevent default context menu on tab right click, closes #656 2019-10-10 19:34:55 +02:00
zadam
c9432990b7 calendar widget styling for dark themes 2019-10-08 20:25:54 +02:00
zadam
9ad521822d mac spellchecker build 2019-10-07 22:17:22 +02:00
zadam
824fb08511 Merge remote-tracking branch 'origin/master' 2019-10-07 20:58:58 +02:00
zadam
cc4c15daf0 spellchecker binaries for windows 2019-10-07 20:58:48 +02:00
Logan Gorence
7718778013 Fix typo in note export screen. (#654) 2019-10-07 08:49:53 +02:00
zadam
a25260353d spellcheck binaries for linux-x64 2019-10-06 22:33:19 +02:00
zadam
c1e8a4b384 spell check support + small options tabs reorganization 2019-10-06 21:35:26 +02:00
zadam
3f2229d9e1 better handling of not detected mime type 2019-10-06 18:28:53 +02:00
FliegendeWurst
8561227622 Import: use upload mime type if mime cannot be detected from filename (#651) 2019-10-06 18:23:39 +02:00
zadam
8859e2ac40 fix opening links from book 2019-10-06 12:33:47 +02:00
zadam
7423b2f4fd book handling of protected notes 2019-10-06 11:21:12 +02:00
zadam
d23e9f1bc4 tar import will sort notes if there is no meta file 2019-10-06 09:49:47 +02:00
zadam
516277a478 added "auto book" displayed on the empty text pages as a replacement for children overview 2019-10-05 20:27:30 +02:00
zadam
cbc7710d81 removed children overview (will be replaced by book) 2019-10-05 12:06:06 +02:00
zadam
ea71e96f72 ability to set book zoom level via label 2019-10-05 12:01:00 +02:00
zadam
59d1cb1833 expand all children button 2019-10-05 11:22:42 +02:00
zadam
7c54ba63ce render notes in book 2019-10-05 10:55:29 +02:00
zadam
5892b5b851 nested note rendering in book 2019-10-05 09:33:31 +02:00
zadam
02eb737b9d book has now zoom 2019-10-04 22:21:14 +02:00
zadam
144e75da9e fix double import of auto generated link relations 2019-10-02 23:28:29 +02:00
zadam
8d14a0d687 fix incorrect import of relations from tar 2019-10-02 23:22:58 +02:00
zadam
dec2c218f7 basic book rendering of code and image notes 2019-10-02 19:40:22 +02:00
zadam
dd147a7209 rename var so it's not misleading 2019-10-01 21:42:36 +02:00
zadam
c3fabcb666 Merge remote-tracking branch 'origin/master' 2019-10-01 21:41:26 +02:00
zadam
35e825b376 fix tooltips 2019-10-01 21:41:20 +02:00
Arne
334a38c493 BackendAPI: Return Note created within createNoteAndRefresh (#647) 2019-10-01 21:40:57 +02:00
zadam
8ec01c73cd skeleton implementation of new "book" note type 2019-10-01 21:11:11 +02:00
88 changed files with 3162 additions and 3030 deletions

15
.gitpod.dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM gitpod/workspace-full
RUN sudo apt-get update \
&& sudo apt-get install -yq --no-install-recommends \
libpng16-16 \
libpng-dev \
pkg-config \
autoconf \
libtool \
build-essential \
nasm \
libx11-dev \
libxkbfile-dev \
&& sudo rm -rf /var/lib/apt/lists/*

View File

@@ -1,7 +1,11 @@
image:
file: .gitpod.dockerfile
tasks: tasks:
- before: nvm install 10 && nvm use 10 - before: nvm install 10 && nvm use 10
init: npm install init: npm install
command: npm run start command: npm run start-server
ports: ports:
- port: 8080 - port: 8080
onOpen: open-preview onOpen: open-preview

View File

@@ -1,4 +1,4 @@
FROM node:12.10.0-alpine FROM node:12.12.0-alpine
# Create app directory # Create app directory
WORKDIR /usr/src/app WORKDIR /usr/src/app

View File

@@ -46,5 +46,5 @@ Use a browser based dev environment
Or clone locally and run Or clone locally and run
``` ```
npm install npm install
npm run start npm run start-server
``` ```

View File

@@ -1,20 +1,26 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BUILD_DIR=./dist/trilium-linux-x64 SRC_DIR=./dist/trilium-linux-x64-src
rm -rf $BUILD_DIR
if [ "$1" != "DONTCOPY" ]
then
./bin/copy-trilium.sh $SRC_DIR
fi
echo "Copying required linux-x64 binaries" echo "Copying required linux-x64 binaries"
rm -r node_modules/sqlite3/lib/binding/* rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r node_modules/pngquant-bin/vendor/* rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/ cp -r bin/deps/linux-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/linux-x64/image/pngquant node_modules/pngquant-bin/vendor/ cp bin/deps/linux-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/linux-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
# rebuild binaries for image operations (pngquant ...) ./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
npm rebuild
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite BUILD_DIR=./dist/trilium-linux-x64
rm -rf $BUILD_DIR
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
@@ -29,3 +35,7 @@ VERSION=`jq -r ".version" package.json`
cd dist cd dist
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64 tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
cd ..
bin/build-debian.sh

View File

@@ -1,27 +1,36 @@
#!/usr/bin/env bash #!/usr/bin/env bash
SRC_DIR=./dist/trilium-mac-x64-src
if [ "$1" != "DONTCOPY" ]
then
./bin/copy-trilium.sh $SRC_DIR
fi
echo "Copying required mac binaries"
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/giflossy/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
cp -r bin/deps/mac-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/mac-x64/image/cjpeg $SRC_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/mac-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/mac-x64/image/gifsicle $SRC_DIR/node_modules/giflossy/vendor/
cp bin/deps/mac-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
cp bin/deps/mac-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns
BUILD_DIR=./dist/trilium-mac-x64 BUILD_DIR=./dist/trilium-mac-x64
rm -rf $BUILD_DIR 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=images/app-icons/mac/icon.icns
# Mac build has by default useless directory level # Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
./bin/reset-local.sh
echo "Zipping mac x64 electron distribution..." echo "Zipping mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json` VERSION=`jq -r ".version" package.json`

View File

@@ -1,40 +1,32 @@
#!/usr/bin/env bash #!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=12.10.0 NODE_VERSION=12.12.0
rm -r $PKG_DIR if [ "$1" != "DONTCOPY" ]
mkdir $PKG_DIR then
cd $PKG_DIR ./bin/copy-trilium.sh $PKG_DIR
fi
cd dist
wget https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz wget https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz
tar xvfJ node-v${NODE_VERSION}-linux-x64.tar.xz tar xvfJ node-v${NODE_VERSION}-linux-x64.tar.xz
rm node-v${NODE_VERSION}-linux-x64.tar.xz rm node-v${NODE_VERSION}-linux-x64.tar.xz
mv node-v${NODE_VERSION}-linux-x64 node
cp -r ../../node_modules/ ./
cp -r ../../images/ ./
cp -r ../../libraries/ ./
cp -r ../../src/ ./
cp -r ../../db/ ./
cp -r ../../package.json ./
cp -r ../../package-lock.json ./
cp -r ../../README.md ./
cp -r ../../LICENSE ./
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 .. cd ..
VERSION=`jq -r ".version" ../package.json` mv dist/node-v${NODE_VERSION}-linux-x64 $PKG_DIR/node
rm -r $PKG_DIR/node_modules/electron*
rm -r $PKG_DIR/node_modules/sqlite3/lib/binding/*
cp -r ./bin/deps/linux-x64/sqlite/node* $PKG_DIR/node_modules/sqlite3/lib/binding/
printf "#!/bin/sh\n./node/bin/node src/www" > $PKG_DIR/trilium.sh
chmod 755 $PKG_DIR/trilium.sh
VERSION=`jq -r ".version" package.json`
cd dist
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server

View File

@@ -1,29 +1,38 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BUILD_DIR=./dist/trilium-windows-x64 SRC_DIR=./dist/trilium-windows-x64-src
rm -rf $BUILD_DIR
if [ "$1" != "DONTCOPY" ]
then
./bin/copy-trilium.sh $SRC_DIR
fi
echo "Copying required windows binaries" echo "Copying required windows binaries"
rm -r node_modules/sqlite3/lib/binding/* rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
rm -r node_modules/mozjpeg/vendor/* rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
rm -r node_modules/pngquant-bin/vendor/* rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
rm -r node_modules/giflossy/vendor/* rm -r $SRC_DIR/node_modules/giflossy/vendor/*
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
cp -r bin/deps/win-x64/sqlite/* node_modules/sqlite3/lib/binding/ cp -r bin/deps/win-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/win-x64/image/cjpeg.exe node_modules/mozjpeg/vendor/ cp bin/deps/win-x64/image/cjpeg.exe $SRC_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/win-x64/image/pngquant.exe node_modules/pngquant-bin/vendor/ cp bin/deps/win-x64/image/pngquant.exe $SRC_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/win-x64/image/gifsicle.exe node_modules/giflossy/vendor/ cp bin/deps/win-x64/image/gifsicle.exe $SRC_DIR/node_modules/giflossy/vendor/
cp bin/deps/win-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
cp bin/deps/win-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico ./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico
BUILD_DIR=./dist/trilium-windows-x64
rm -rf $BUILD_DIR
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
# removing software WebGL binaries because they are pretty huge and not necessary # removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader rm -r $BUILD_DIR/swiftshader
./bin/reset-local.sh
echo "Zipping windows x64 electron distribution..." echo "Zipping windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json` VERSION=`jq -r ".version" package.json`

View File

@@ -1,21 +1,23 @@
#!/usr/bin/env bash #!/usr/bin/env bash
rm -r node_modules
npm install
echo "Deleting existing builds" echo "Deleting existing builds"
rm -r dist/* rm -r dist/*
bin/build-win-x64.sh SRC_DIR=dist/trilium-src
bin/build-mac-x64.sh bin/copy-trilium.sh $SRC_DIR
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development # we'll just copy the same SRC dir to all the builds so we don't have to do npm install in each separately
bin/build-linux-x64.sh cp -r $SRC_DIR ./dist/trilium-linux-x64-src
cp -r $SRC_DIR ./dist/trilium-linux-x64-server
cp -r $SRC_DIR ./dist/trilium-windows-x64-src
cp -r $SRC_DIR ./dist/trilium-mac-x64-src
# this needs to be run after linux build bin/build-win-x64.sh DONTCOPY
bin/build-debian.sh
bin/build-server.sh bin/build-mac-x64.sh DONTCOPY
bin/build-linux-x64.sh DONTCOPY
bin/build-server.sh DONTCOPY

32
bin/copy-trilium.sh Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of target directory"
exit 1
fi
DIR=$1
rm -rf $DIR
mkdir $DIR
echo "Copying Trilium to build directory $DIR"
cp -r images $DIR/
cp -r libraries $DIR/
cp -r src $DIR/
cp -r db $DIR/
cp -r package.json $DIR/
cp -r package-lock.json $DIR/
cp -r README.md $DIR/
cp -r LICENSE $DIR/
cp -r config-sample.ini $DIR/
cp -r electron.js $DIR/
# run in subshell (so we return to original dir)
(cd $DIR && npm install --only=prod)
rm -r $DIR/node_modules/cld/deps
find $DIR/libraries -name "*.map" -type f -delete
find $DIR/libraries -name "hunspell.lib" -type f -delete

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,3 +0,0 @@
#!/usr/bin/env bash
./node_modules/.bin/electron-rebuild --arch=x64

Binary file not shown.

View File

@@ -0,0 +1,5 @@
INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced)
VALUES ('spellCheckEnabled', 'true', '2018-07-29T18:31:00.874Z', '2018-07-29T18:31:00.874Z', 0);
INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced)
VALUES ('spellCheckLanguageCode', 'en-US', '2018-07-29T18:31:00.874Z', '2018-07-29T18:31:00.874Z', 0);

View File

@@ -396,7 +396,7 @@ the backend.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line310">line 310</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line312">line 312</a>
</li></ul></dd> </li></ul></dd>
@@ -1533,7 +1533,7 @@ the backend.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line315">line 315</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line317">line 317</a>
</li></ul></dd> </li></ul></dd>
@@ -1997,7 +1997,7 @@ the backend.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line239">line 239</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line241">line 241</a>
</li></ul></dd> </li></ul></dd>
@@ -2765,7 +2765,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line258">line 258</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line260">line 260</a>
</li></ul></dd> </li></ul></dd>
@@ -3418,7 +3418,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line230">line 230</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line232">line 232</a>
</li></ul></dd> </li></ul></dd>
@@ -3596,7 +3596,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line249">line 249</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line251">line 251</a>
</li></ul></dd> </li></ul></dd>
@@ -3751,7 +3751,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line267">line 267</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line269">line 269</a>
</li></ul></dd> </li></ul></dd>
@@ -3901,7 +3901,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line222">line 222</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line224">line 224</a>
</li></ul></dd> </li></ul></dd>
@@ -4427,7 +4427,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line287">line 287</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line289">line 289</a>
</li></ul></dd> </li></ul></dd>
@@ -4560,7 +4560,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line274">line 274</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line276">line 276</a>
</li></ul></dd> </li></ul></dd>
@@ -4935,7 +4935,7 @@ transactional by default.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line300">line 300</a> <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line302">line 302</a>
</li></ul></dd> </li></ul></dd>

View File

@@ -237,9 +237,11 @@ function BackendScriptApi(currentNote, apiParams) {
* @returns {Promise&lt;{note: Note, branch: Branch}>} object contains newly created entities note and branch * @returns {Promise&lt;{note: Note, branch: Branch}>} object contains newly created entities note and branch
*/ */
this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) { this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) {
await noteService.createNote(parentNoteId, title, content, extraOptions); const ret = await noteService.createNote(parentNoteId, title, content, extraOptions);
ws.refreshTree(); ws.refreshTree();
return ret;
}; };
/** /**
@@ -343,7 +345,8 @@ function BackendScriptApi(currentNote, apiParams) {
this.getAppInfo = () => appInfo this.getAppInfo = () => appInfo
} }
module.exports = BackendScriptApi;</code></pre> module.exports = BackendScriptApi;
</code></pre>
</article> </article>
</section> </section>

View File

@@ -131,6 +131,116 @@
<h4 class="name" id="$container"><span class="type-signature"></span>$container<span class="type-signature"></span></h4>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>container</code></td>
<td class="type">
<span class="param-type">jQuery</span>
</td>
<td class="description last">of all the rendered script content</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#line23">line 23</a>
</li></ul></dd>
</dl>
<h4 class="name" id="currentNote"><span class="type-signature"></span>currentNote<span class="type-signature"></span></h4> <h4 class="name" id="currentNote"><span class="type-signature"></span>currentNote<span class="type-signature"></span></h4>
@@ -223,7 +333,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line25">line 25</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line28">line 28</a>
</li></ul></dd> </li></ul></dd>
@@ -336,7 +446,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line27">line 27</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line30">line 30</a>
</li></ul></dd> </li></ul></dd>
@@ -442,7 +552,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line36">line 36</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line39">line 39</a>
</li></ul></dd> </li></ul></dd>
@@ -552,7 +662,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line23">line 23</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line26">line 26</a>
</li></ul></dd> </li></ul></dd>
@@ -661,7 +771,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line36">line 36</a>
</li></ul></dd> </li></ul></dd>
@@ -790,7 +900,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line61">line 61</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line64">line 64</a>
</li></ul></dd> </li></ul></dd>
@@ -945,7 +1055,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line45">line 45</a> <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> </li></ul></dd>
@@ -1100,7 +1210,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line80">line 80</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line83">line 83</a>
</li></ul></dd> </li></ul></dd>
@@ -1280,7 +1390,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line269">line 269</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line272">line 272</a>
</li></ul></dd> </li></ul></dd>
@@ -1413,7 +1523,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line229">line 229</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line232">line 232</a>
</li></ul></dd> </li></ul></dd>
@@ -1519,7 +1629,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line275">line 275</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line278">line 278</a>
</li></ul></dd> </li></ul></dd>
@@ -1625,7 +1735,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line281">line 281</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line284">line 284</a>
</li></ul></dd> </li></ul></dd>
@@ -1784,7 +1894,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line332">line 332</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line335">line 335</a>
</li></ul></dd> </li></ul></dd>
@@ -1891,7 +2001,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line222">line 222</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line225">line 225</a>
</li></ul></dd> </li></ul></dd>
@@ -2046,7 +2156,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line341">line 341</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line344">line 344</a>
</li></ul></dd> </li></ul></dd>
@@ -2202,7 +2312,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line190">line 190</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line193">line 193</a>
</li></ul></dd> </li></ul></dd>
@@ -2403,7 +2513,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line202">line 202</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line205">line 205</a>
</li></ul></dd> </li></ul></dd>
@@ -2509,7 +2619,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line323">line 323</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line326">line 326</a>
</li></ul></dd> </li></ul></dd>
@@ -2664,7 +2774,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line350">line 350</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line353">line 353</a>
</li></ul></dd> </li></ul></dd>
@@ -2773,7 +2883,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line296">line 296</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line299">line 299</a>
</li></ul></dd> </li></ul></dd>
@@ -2928,7 +3038,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line304">line 304</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line307">line 307</a>
</li></ul></dd> </li></ul></dd>
@@ -3061,7 +3171,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line236">line 236</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line239">line 239</a>
</li></ul></dd> </li></ul></dd>
@@ -3167,7 +3277,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line315">line 315</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line318">line 318</a>
</li></ul></dd> </li></ul></dd>
@@ -3255,7 +3365,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line260">line 260</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line263">line 263</a>
</li></ul></dd> </li></ul></dd>
@@ -3406,7 +3516,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line208">line 208</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line211">line 211</a>
</li></ul></dd> </li></ul></dd>
@@ -3539,7 +3649,7 @@ note.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line214">line 214</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line217">line 217</a>
</li></ul></dd> </li></ul></dd>
@@ -3700,7 +3810,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line130">line 130</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line133">line 133</a>
</li></ul></dd> </li></ul></dd>
@@ -3860,7 +3970,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line178">line 178</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> </li></ul></dd>
@@ -4016,7 +4126,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line160">line 160</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line163">line 163</a>
</li></ul></dd> </li></ul></dd>
@@ -4167,7 +4277,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line310">line 310</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line313">line 313</a>
</li></ul></dd> </li></ul></dd>
@@ -4304,7 +4414,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line252">line 252</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line255">line 255</a>
</li></ul></dd> </li></ul></dd>
@@ -4441,7 +4551,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line244">line 244</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line247">line 247</a>
</li></ul></dd> </li></ul></dd>

View File

@@ -30,7 +30,10 @@
<h2><span class="attribs"><span class="type-signature"></span></span>NoteShort<span class="signature">()</span><span class="type-signature"></span></h2> <h2><span class="attribs"><span class="type-signature"></span></span>NoteShort<span class="signature">()</span><span class="type-signature"></span></h2>
<div class="class-description">This note's representation is used in note tree and is kept in TreeCache.</div> <div class="class-description">FIXME: rethink how attributes are cached in Note entities since they are long lived inside the cache.
Attribute cache should be limited to "transaction".
This note's representation is used in note tree and is kept in TreeCache.</div>
</header> </header>
@@ -93,7 +96,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line13">line 13</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line16">line 16</a>
</li></ul></dd> </li></ul></dd>
@@ -183,7 +186,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line26">line 26</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line29">line 29</a>
</li></ul></dd> </li></ul></dd>
@@ -241,7 +244,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line28">line 28</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line31">line 31</a>
</li></ul></dd> </li></ul></dd>
@@ -299,7 +302,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line20">line 20</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line23">line 23</a>
</li></ul></dd> </li></ul></dd>
@@ -357,7 +360,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line24">line 24</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line27">line 27</a>
</li></ul></dd> </li></ul></dd>
@@ -415,7 +418,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line16">line 16</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line19">line 19</a>
</li></ul></dd> </li></ul></dd>
@@ -473,7 +476,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line18">line 18</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line21">line 21</a>
</li></ul></dd> </li></ul></dd>
@@ -531,7 +534,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line22">line 22</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line25">line 25</a>
</li></ul></dd> </li></ul></dd>
@@ -679,7 +682,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line166">line 166</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line169">line 169</a>
</li></ul></dd> </li></ul></dd>
@@ -846,7 +849,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line106">line 106</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line109">line 109</a>
</li></ul></dd> </li></ul></dd>
@@ -1020,7 +1023,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line177">line 177</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line180">line 180</a>
</li></ul></dd> </li></ul></dd>
@@ -1126,7 +1129,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line57">line 57</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line60">line 60</a>
</li></ul></dd> </li></ul></dd>
@@ -1228,7 +1231,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line71">line 71</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line74">line 74</a>
</li></ul></dd> </li></ul></dd>
@@ -1330,7 +1333,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line93">line 93</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line96">line 96</a>
</li></ul></dd> </li></ul></dd>
@@ -1432,7 +1435,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line98">line 98</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line101">line 101</a>
</li></ul></dd> </li></ul></dd>
@@ -1583,7 +1586,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line199">line 199</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line202">line 202</a>
</li></ul></dd> </li></ul></dd>
@@ -1750,7 +1753,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line132">line 132</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line135">line 135</a>
</li></ul></dd> </li></ul></dd>
@@ -1917,7 +1920,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line124">line 124</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line127">line 127</a>
</li></ul></dd> </li></ul></dd>
@@ -2072,7 +2075,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line211">line 211</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line214">line 214</a>
</li></ul></dd> </li></ul></dd>
@@ -2178,7 +2181,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line83">line 83</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line86">line 86</a>
</li></ul></dd> </li></ul></dd>
@@ -2280,7 +2283,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line88">line 88</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line91">line 91</a>
</li></ul></dd> </li></ul></dd>
@@ -2431,7 +2434,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line205">line 205</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line208">line 208</a>
</li></ul></dd> </li></ul></dd>
@@ -2598,7 +2601,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line148">line 148</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line151">line 151</a>
</li></ul></dd> </li></ul></dd>
@@ -2765,7 +2768,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line140">line 140</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line143">line 143</a>
</li></ul></dd> </li></ul></dd>
@@ -2920,7 +2923,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line223">line 223</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line226">line 226</a>
</li></ul></dd> </li></ul></dd>
@@ -3090,7 +3093,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line233">line 233</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line236">line 236</a>
</li></ul></dd> </li></ul></dd>
@@ -3241,7 +3244,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line217">line 217</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line220">line 220</a>
</li></ul></dd> </li></ul></dd>
@@ -3351,7 +3354,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line257">line 257</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line260">line 260</a>
</li></ul></dd> </li></ul></dd>
@@ -3525,7 +3528,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line157">line 157</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line160">line 160</a>
</li></ul></dd> </li></ul></dd>
@@ -3631,7 +3634,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line65">line 65</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line68">line 68</a>
</li></ul></dd> </li></ul></dd>
@@ -3782,7 +3785,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line187">line 187</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line190">line 190</a>
</li></ul></dd> </li></ul></dd>
@@ -3937,7 +3940,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line193">line 193</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line196">line 196</a>
</li></ul></dd> </li></ul></dd>
@@ -4048,7 +4051,7 @@ Cache is note instance scoped.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line248">line 248</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line251">line 251</a>
</li></ul></dd> </li></ul></dd>
@@ -4132,7 +4135,7 @@ Cache is note instance scoped.
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line32">line 32</a> <a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line35">line 35</a>
</li></ul></dd> </li></ul></dd>

View File

@@ -35,6 +35,9 @@ const RELATION = 'relation';
const RELATION_DEFINITION = 'relation-definition'; const RELATION_DEFINITION = 'relation-definition';
/** /**
* FIXME: rethink how attributes are cached in Note entities since they are long lived inside the cache.
* Attribute cache should be limited to "transaction".
*
* This note's representation is used in note tree and is kept in TreeCache. * This note's representation is used in note tree and is kept in TreeCache.
*/ */
class NoteShort { class NoteShort {

View File

@@ -303,7 +303,7 @@
<dt class="tag-source">Source:</dt> <dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li> <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#line67">line 67</a> <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line70">line 70</a>
</li></ul></dd> </li></ul></dd>

View File

@@ -44,9 +44,12 @@ import StandardWidget from '../widgets/standard_widget.js';
* @constructor * @constructor
* @hideconstructor * @hideconstructor
*/ */
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) { function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
const $pluginButtons = $("#plugin-buttons"); const $pluginButtons = $("#plugin-buttons");
/** @property {jQuery} container of all the rendered script content */
this.$container = $container;
/** @property {object} note where script started executing */ /** @property {object} note where script started executing */
this.startNote = startNote; this.startNote = startNote;
/** @property {object} note where script is currently executing */ /** @property {object} note where script is currently executing */
@@ -322,7 +325,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
* @return {boolean} returns true if the original note is still loaded, false if user switched to another * @return {boolean} returns true if the original note is still loaded, false if user switched to another
*/ */
this.isNoteStillActive = () => { this.isNoteStillActive = () => {
return this.originEntity.noteId === tabContext.noteId; return tabContext.note &amp;&amp; this.originEntity.noteId === tabContext.note.noteId;
}; };
/** /**

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
const electron = require('electron'); const {app, globalShortcut, BrowserWindow} = require('electron');
const path = require('path'); const path = require('path');
const log = require('./src/services/log'); const log = require('./src/services/log');
const sqlInit = require('./src/services/sql_init'); const sqlInit = require('./src/services/sql_init');
@@ -10,10 +10,6 @@ const port = require('./src/services/port');
const env = require('./src/services/env'); const env = require('./src/services/env');
const appIconService = require('./src/services/app_icon'); const appIconService = require('./src/services/app_icon');
const windowStateKeeper = require('electron-window-state'); const windowStateKeeper = require('electron-window-state');
const contextMenu = require('electron-context-menu');
const app = electron.app;
const globalShortcut = electron.globalShortcut;
// Adds debug features like hotkeys for triggering dev tools and reload // Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')(); require('electron-debug')();
@@ -25,25 +21,25 @@ let mainWindow;
require('electron-dl')({ saveAs: true }); require('electron-dl')({ saveAs: true });
contextMenu({ // contextMenu({
menu: (actions, params, browserWindow) => [ // menu: (actions, params, browserWindow) => [
actions.cut(), // actions.cut(),
actions.copy(), // actions.copy(),
actions.copyLink(), // actions.copyLink(),
actions.paste(), // actions.paste(),
{ // {
label: 'Search DuckDuckGo for “{selection}”', // label: 'Search DuckDuckGo for “{selection}”',
// Only show it when right-clicking text // // Only show it when right-clicking text
visible: params.selectionText.trim().length > 0, // visible: params.selectionText.trim().length > 0,
click: () => { // click: () => {
const {shell} = require('electron'); // const {shell} = require('electron');
//
shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`); // shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`);
} // }
}, // },
actions.inspect() // actions.inspect()
] // ]
}); // });
function onClosed() { function onClosed() {
// Dereference the window // Dereference the window
@@ -66,7 +62,7 @@ async function createMainWindow() {
defaultHeight: 800 defaultHeight: 800
}); });
const win = new electron.BrowserWindow({ const win = new BrowserWindow({
x: mainWindowState.x, x: mainWindowState.x,
y: mainWindowState.y, y: mainWindowState.y,
width: mainWindowState.width, width: mainWindowState.width,

4367
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "trilium", "name": "trilium",
"productName": "Trilium Notes", "productName": "Trilium Notes",
"description": "Trilium Notes", "description": "Trilium Notes",
"version": "0.35.2", "version": "0.36.0-beta",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"main": "electron.js", "main": "electron.js",
"bin": { "bin": {
@@ -17,8 +17,7 @@
"start-electron": "TRILIUM_ENV=dev electron . --disable-gpu", "start-electron": "TRILIUM_ENV=dev electron . --disable-gpu",
"build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js", "build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
"build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js", "build-frontend-docs": "./node_modules/.bin/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": { "dependencies": {
"async-mutex": "0.1.4", "async-mutex": "0.1.4",
@@ -31,20 +30,20 @@
"dayjs": "1.8.16", "dayjs": "1.8.16",
"debug": "4.1.1", "debug": "4.1.1",
"ejs": "2.7.1", "ejs": "2.7.1",
"electron-context-menu": "0.15.0",
"electron-debug": "3.0.1", "electron-debug": "3.0.1",
"electron-dl": "1.14.0", "electron-dl": "1.14.0",
"electron-find": "1.0.6", "electron-find": "1.0.6",
"electron-spellchecker": "2.2.0",
"electron-window-state": "5.0.3", "electron-window-state": "5.0.3",
"express": "4.17.1", "express": "4.17.1",
"express-session": "1.16.2", "express-session": "1.17.0",
"file-type": "12.3.0", "file-type": "12.3.0",
"fs-extra": "8.1.0", "fs-extra": "8.1.0",
"helmet": "3.21.1", "helmet": "3.21.1",
"html": "1.0.0", "html": "1.0.0",
"html2plaintext": "2.1.2", "html2plaintext": "2.1.2",
"http-proxy-agent": "^2.1.0", "http-proxy-agent": "2.1.0",
"https-proxy-agent": "^2.2.2", "https-proxy-agent": "3.0.0",
"image-type": "4.1.0", "image-type": "4.1.0",
"imagemin": "7.0.0", "imagemin": "7.0.0",
"imagemin-giflossy": "5.1.10", "imagemin-giflossy": "5.1.10",
@@ -70,7 +69,7 @@
"simple-node-logger": "18.12.23", "simple-node-logger": "18.12.23",
"sqlite": "3.0.3", "sqlite": "3.0.3",
"sqlite3": "4.1.0", "sqlite3": "4.1.0",
"string-similarity": "^3.0.0", "string-similarity": "3.0.0",
"tar-stream": "2.1.0", "tar-stream": "2.1.0",
"turndown": "5.0.3", "turndown": "5.0.3",
"turndown-plugin-gfm": "1.0.2", "turndown-plugin-gfm": "1.0.2",
@@ -85,7 +84,7 @@
"electron-installer-debian": "2.0.1", "electron-installer-debian": "2.0.1",
"electron-packager": "14.0.6", "electron-packager": "14.0.6",
"electron-rebuild": "1.8.6", "electron-rebuild": "1.8.6",
"jsdoc": "^3.6.3", "jsdoc": "3.6.3",
"lorem-ipsum": "2.0.3", "lorem-ipsum": "2.0.3",
"xo": "0.25.3" "xo": "0.25.3"
}, },

View File

@@ -88,7 +88,10 @@ app.use((req, res, next) => {
// error handler // error handler
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
if (err && err.message && err.message.includes("Invalid package")) { if (err && err.message && (
err.message.includes("Invalid package")
|| (err.message.includes("Router not found for request") && err.message.includes("node_modules"))
)) {
// electron 6 outputs a lot of such errors which do not seem important // electron 6 outputs a lot of such errors which do not seem important
} }
else { else {

View File

@@ -29,6 +29,7 @@ import macInit from './services/mac_init.js';
import cssLoader from './services/css_loader.js'; import cssLoader from './services/css_loader.js';
import dateNoteService from './services/date_notes.js'; import dateNoteService from './services/date_notes.js';
import sidebarService from './services/sidebar.js'; import sidebarService from './services/sidebar.js';
import importService from './services/import.js';
window.glob.isDesktop = utils.isDesktop; window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile; window.glob.isMobile = utils.isMobile;
@@ -177,3 +178,7 @@ entrypoints.registerEntrypoints();
noteTooltipService.setupGlobalTooltip(); noteTooltipService.setupGlobalTooltip();
noteAutocompleteService.init(); noteAutocompleteService.init();
if (utils.isElectron()) {
import("./services/spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
}

View File

@@ -1,16 +1,11 @@
import treeService from '../services/tree.js';
import utils from '../services/utils.js'; import utils from '../services/utils.js';
import treeUtils from "../services/tree_utils.js"; import treeUtils from "../services/tree_utils.js";
import server from "../services/server.js"; import importService from "../services/import.js";
import infoService from "../services/info.js";
import ws from "../services/ws.js";
const $dialog = $("#import-dialog"); const $dialog = $("#import-dialog");
const $form = $("#import-form"); const $form = $("#import-form");
const $noteTitle = $dialog.find(".import-note-title"); const $noteTitle = $dialog.find(".import-note-title");
const $fileUploadInput = $("#import-file-upload-input"); const $fileUploadInput = $("#import-file-upload-input");
const $importProgressCountWrapper = $("#import-progress-count-wrapper");
const $importProgressCount = $("#import-progress-count");
const $importButton = $("#import-button"); const $importButton = $("#import-button");
const $safeImportCheckbox = $("#safe-import-checkbox"); const $safeImportCheckbox = $("#safe-import-checkbox");
const $shrinkImagesCheckbox = $("#shrink-images-checkbox"); const $shrinkImagesCheckbox = $("#shrink-images-checkbox");
@@ -18,16 +13,11 @@ const $textImportedAsTextCheckbox = $("#text-imported-as-text-checkbox");
const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox"); const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox");
const $explodeArchivesCheckbox = $("#explode-archives-checkbox"); const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
let importId; let parentNoteId = null;
let importIntoNoteId = null;
export async function showDialog(node) { export async function showDialog(node) {
utils.closeActiveDialog(); utils.closeActiveDialog();
// each opening of the dialog resets the importId so we don't associate it with previous imports anymore
importId = '';
$importProgressCountWrapper.hide();
$importProgressCount.text('0');
$fileUploadInput.val('').change(); // to trigger Import button disabling listener below $fileUploadInput.val('').change(); // to trigger Import button disabling listener below
$safeImportCheckbox.prop("checked", true); $safeImportCheckbox.prop("checked", true);
@@ -38,9 +28,9 @@ export async function showDialog(node) {
glob.activeDialog = $dialog; glob.activeDialog = $dialog;
importIntoNoteId = node.data.noteId; parentNoteId = node.data.noteId;
$noteTitle.text(await treeUtils.getNoteTitle(importIntoNoteId)); $noteTitle.text(await treeUtils.getNoteTitle(parentNoteId));
$dialog.modal(); $dialog.modal();
} }
@@ -49,18 +39,14 @@ $form.submit(() => {
// disabling so that import is not triggered again. // disabling so that import is not triggered again.
$importButton.attr("disabled", "disabled"); $importButton.attr("disabled", "disabled");
importIntoNote(importIntoNoteId); importIntoNote(parentNoteId);
return false; return false;
}); });
async function importIntoNote(importNoteId) { async function importIntoNote(parentNoteId) {
const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
// we generate it here (and not on opening) for the case when you try to import multiple times from the same
// dialog (which shouldn't happen, but still ...)
importId = utils.randomString(10);
const options = { const options = {
safeImport: boolToString($safeImportCheckbox), safeImport: boolToString($safeImportCheckbox),
shrinkImages: boolToString($shrinkImagesCheckbox), shrinkImages: boolToString($shrinkImagesCheckbox),
@@ -69,73 +55,15 @@ async function importIntoNote(importNoteId) {
explodeArchives: boolToString($explodeArchivesCheckbox) explodeArchives: boolToString($explodeArchivesCheckbox)
}; };
await uploadFiles(importNoteId, files, options);
$dialog.modal('hide'); $dialog.modal('hide');
}
export async function uploadFiles(importNoteId, files, options) { await importService.uploadFiles(parentNoteId, files, options);
if (files.length === 0) {
return;
}
let noteId;
for (const file of files) {
const formData = new FormData();
formData.append('upload', file);
formData.append('importId', importId);
for (const key in options) {
formData.append(key, options[key]);
}
({noteId} = await $.ajax({
url: baseApiUrl + 'notes/' + importNoteId + '/import',
headers: server.getHeaders(),
data: formData,
dataType: 'json',
type: 'POST',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
}));
}
infoService.showMessage("Import finished successfully.");
await treeService.reloadNote(importNoteId);
if (noteId) {
const node = await treeService.activateNote(noteId);
node.setExpanded(true);
}
} }
function boolToString($el) { function boolToString($el) {
return $el.is(":checked") ? "true" : "false"; return $el.is(":checked") ? "true" : "false";
} }
ws.subscribeToMessages(async message => {
if (message.type === 'import-error') {
infoService.showError(message.message);
$dialog.modal('hide');
return;
}
if (!message.importId || message.importId !== importId) {
// incoming messages must correspond to this import instance
return;
}
if (message.type === 'import-progress-count') {
$importProgressCountWrapper.slideDown();
$importProgressCount.text(message.progressCount);
}
});
$fileUploadInput.change(() => { $fileUploadInput.change(() => {
if ($fileUploadInput.val()) { if ($fileUploadInput.val()) {
$importButton.removeAttr("disabled"); $importButton.removeAttr("disabled");

View File

@@ -62,14 +62,4 @@ $list.on('change', () => {
else { else {
$content.text("Preview isn't available for this note type."); $content.text("Preview isn't available for this note type.");
} }
}); });
$(document).on('click', "a[data-action='note-revision']", event => {
const linkEl = $(event.target);
const noteId = linkEl.attr('data-note-path');
const noteRevisionId = linkEl.attr('data-note-revision-id');
showNoteRevisionsDialog(noteId, noteRevisionId);
return false;
});

View File

@@ -19,8 +19,7 @@ export async function showDialog() {
import('./options/appearance.js'), import('./options/appearance.js'),
import('./options/code_notes.js'), import('./options/code_notes.js'),
import('./options/change_password.js'), import('./options/change_password.js'),
import('./options/note_revisions.js'), import('./options/other.js'),
import('./options/protected_session.js'),
import('./options/sidebar.js'), import('./options/sidebar.js'),
import('./options/sync.js'), import('./options/sync.js'),
])) ]))

View File

@@ -1,20 +0,0 @@
import server from "../../services/server.js";
import infoService from "../../services/info.js";
export default class NoteRevisionsOptions {
constructor() {
this.$form = $("#note-revision-snapshot-time-interval-form");
this.$timeInterval = $("#note-revision-snapshot-time-interval-in-seconds");
this.$form.submit(() => {
const opts = { 'noteRevisionSnapshotTimeInterval': this.$timeInterval.val() };
server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
return false;
});
}
optionsLoaded(options) {
this.$timeInterval.val(options['noteRevisionSnapshotTimeInterval']);
}
}

View File

@@ -0,0 +1,54 @@
import optionsService from "../../services/options.js";
import server from "../../services/server.js";
import infoService from "../../services/info.js";
export default class ProtectedSessionOptions {
constructor() {
this.$spellCheckEnabled = $("#spell-check-enabled");
this.$spellCheckLanguageCode = $("#spell-check-language-code");
this.$protectedSessionTimeout = $("#protected-session-timeout-in-seconds");
this.$noteRevisionsTimeInterval = $("#note-revision-snapshot-time-interval-in-seconds");
this.$spellCheckEnabled.change(() => {
const opts = { 'spellCheckEnabled': this.$spellCheckEnabled.is(":checked") ? "true" : "false" };
server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
return false;
});
this.$spellCheckLanguageCode.change(() => {
const opts = { 'spellCheckLanguageCode': this.$spellCheckLanguageCode.val() };
server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
return false;
});
this.$protectedSessionTimeout.change(() => {
const protectedSessionTimeout = this.$protectedSessionTimeout.val();
server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
optionsService.reloadOptions();
infoService.showMessage("Options change have been saved.");
});
return false;
});
this.$noteRevisionsTimeInterval.change(() => {
const opts = { 'noteRevisionSnapshotTimeInterval': this.$noteRevisionsTimeInterval.val() };
server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
return false;
});
}
optionsLoaded(options) {
this.$spellCheckEnabled.prop("checked", options['spellCheckEnabled'] === 'true');
this.$spellCheckLanguageCode.val(options['spellCheckLanguageCode']);
this.$protectedSessionTimeout.val(options['protectedSessionTimeout']);
this.$noteRevisionsTimeInterval.val(options['noteRevisionSnapshotTimeInterval']);
}
}

View File

@@ -1,28 +0,0 @@
import optionsService from "../../services/options.js";
import server from "../../services/server.js";
import infoService from "../../services/info.js";
export default class ProtectedSessionOptions {
constructor() {
this.$form = $("#protected-session-timeout-form");
this.$protectedSessionTimeout = $("#protected-session-timeout-in-seconds");
this.$form.submit(() => this.save());
}
optionsLoaded(options) {
this.$protectedSessionTimeout.val(options['protectedSessionTimeout']);
}
save() {
const protectedSessionTimeout = this.$protectedSessionTimeout.val();
server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
optionsService.reloadOptions();
infoService.showMessage("Options change have been saved.");
});
return false;
}
}

View File

@@ -8,8 +8,8 @@ async function getAndExecuteBundle(noteId, originEntity = null) {
return await executeBundle(bundle, originEntity); return await executeBundle(bundle, originEntity);
} }
async function executeBundle(bundle, originEntity, tabContext) { async function executeBundle(bundle, originEntity, tabContext, $container) {
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext); const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext, $container);
try { try {
return await (function () { return await (function () {

View File

@@ -30,9 +30,9 @@ const dragAndDropSetup = {
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) { if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
const importDialog = await import('../dialogs/import.js'); const importService = await import('./import.js');
importDialog.uploadFiles(node.data.noteId, files, { importService.uploadFiles(node.data.noteId, files, {
safeImport: true, safeImport: true,
shrinkImages: true, shrinkImages: true,
textImportedAsText: true, textImportedAsText: true,

View File

@@ -172,6 +172,19 @@ function registerEntrypoints() {
utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor); utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor);
utils.bindGlobalShortcut('ctrl+=', zoomService.increaseZoomFactor); utils.bindGlobalShortcut('ctrl+=', zoomService.increaseZoomFactor);
} }
$(document).on('click', "a[data-action='note-revision']", async event => {
const linkEl = $(event.target);
const noteId = linkEl.attr('data-note-path');
const noteRevisionId = linkEl.attr('data-note-revision-id');
const attributesDialog = await import("../dialogs/note_revisions.js");
attributesDialog.showNoteRevisionsDialog(noteId, noteRevisionId);
return false;
});
} }
export default { export default {

View File

@@ -16,9 +16,12 @@ import StandardWidget from '../widgets/standard_widget.js';
* @constructor * @constructor
* @hideconstructor * @hideconstructor
*/ */
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) { function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
const $pluginButtons = $("#plugin-buttons"); const $pluginButtons = $("#plugin-buttons");
/** @property {jQuery} container of all the rendered script content */
this.$container = $container;
/** @property {object} note where script started executing */ /** @property {object} note where script started executing */
this.startNote = startNote; this.startNote = startNote;
/** @property {object} note where script is currently executing */ /** @property {object} note where script is currently executing */

View File

@@ -0,0 +1,66 @@
import infoService from "./info.js";
import treeService from "./tree.js";
import server from "./server.js";
import ws from "./ws.js";
import utils from "./utils.js";
export async function uploadFiles(parentNoteId, files, options) {
if (files.length === 0) {
return;
}
const importId = utils.randomString(10);
let noteId;
let counter = 0;
for (const file of files) {
counter++;
const formData = new FormData();
formData.append('upload', file);
formData.append('importId', importId);
formData.append('last', counter === files.length ? "true" : "false");
for (const key in options) {
formData.append(key, options[key]);
}
({noteId} = await $.ajax({
url: baseApiUrl + 'notes/' + parentNoteId + '/import',
headers: server.getHeaders(),
data: formData,
dataType: 'json',
type: 'POST',
timeout: 60 * 60 * 1000,
contentType: false, // NEEDED, DON'T REMOVE THIS
processData: false, // NEEDED, DON'T REMOVE THIS
}));
}
}
ws.subscribeToMessages(async message => {
if (message.type === 'import-error') {
infoService.showError(message.message);
return;
}
if (message.type === 'import-progress-count') {
infoService.showMessage("Import in progress: " + message.progressCount, 1000);
}
if (message.type === 'import-succeeded') {
infoService.showMessage("Import finished successfully.", 5000);
await treeService.reloadNote(message.parentNoteId);
if (message.importedNoteId) {
const node = await treeService.activateNote(message.importedNoteId);
node.setExpanded(true);
}
}
});
export default {
uploadFiles
}

View File

@@ -1,13 +1,13 @@
import ws from "./ws.js"; import ws from "./ws.js";
import utils from "./utils.js"; import utils from "./utils.js";
function showMessage(message) { function showMessage(message, delay = 3000) {
console.debug(utils.now(), "message: ", message); console.debug(utils.now(), "message: ", message);
$.notify({ $.notify({
icon: 'jam jam-check', icon: 'jam jam-check',
message: message message: message
}, getNotifySettings('success', 3000)); }, getNotifySettings('success', delay));
} }
function showAndLogError(message, delay = 10000) { function showAndLogError(message, delay = 10000) {

View File

@@ -14,20 +14,24 @@ function getNotePathFromUrl(url) {
} }
} }
async function createNoteLink(notePath, noteTitle = null) { async function createNoteLink(notePath, noteTitle = null, tooltip = true) {
if (!noteTitle) { if (!noteTitle) {
const noteId = treeUtils.getNoteIdFromNotePath(notePath); const noteId = treeUtils.getNoteIdFromNotePath(notePath);
noteTitle = await treeUtils.getNoteTitle(noteId); noteTitle = await treeUtils.getNoteTitle(noteId);
} }
const noteLink = $("<a>", { const $noteLink = $("<a>", {
href: 'javascript:', href: 'javascript:',
text: noteTitle text: noteTitle
}).attr('data-action', 'note') }).attr('data-action', 'note')
.attr('data-note-path', notePath); .attr('data-note-path', notePath);
return noteLink; if (!tooltip) {
$noteLink.addClass("no-tooltip-preview");
}
return $noteLink;
} }
async function createNoteLinkWithPath(notePath, noteTitle = null) { async function createNoteLinkWithPath(notePath, noteTitle = null) {
@@ -113,7 +117,7 @@ function addTextToEditor(text) {
} }
} }
function tabContextMenu(e) { function newTabContextMenu(e) {
const $link = $(e.target); const $link = $(e.target);
const notePath = getNotePathFromLink($link); const notePath = getNotePathFromLink($link);
@@ -138,9 +142,9 @@ function tabContextMenu(e) {
}); });
} }
$(document).on('contextmenu', '.note-detail-text a', tabContextMenu); $(document).on('contextmenu', '.note-detail-text a', newTabContextMenu);
$(document).on('contextmenu', "a[data-action='note']", tabContextMenu); $(document).on('contextmenu', "a[data-action='note']", newTabContextMenu);
$(document).on('contextmenu', ".note-detail-render a", tabContextMenu); $(document).on('contextmenu', ".note-detail-render a", newTabContextMenu);
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior // 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 // of opening the link in new window/tab
@@ -159,6 +163,7 @@ $(document).on('mousedown', '.note-detail-text a', function (e) {
} }
}); });
$(document).on('mousedown', '.note-detail-book a', goToLink);
$(document).on('mousedown', '.note-detail-render a', goToLink); $(document).on('mousedown', '.note-detail-render a', goToLink);
$(document).on('mousedown', '.note-detail-text.ck-read-only a', goToLink); $(document).on('mousedown', '.note-detail-text.ck-read-only a', goToLink);
$(document).on('mousedown', 'span.ck-button__label', e => { $(document).on('mousedown', 'span.ck-button__label', e => {

View File

@@ -345,9 +345,9 @@ $tabContentsContainer.on("drop", async e => {
const files = [...e.originalEvent.dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation const files = [...e.originalEvent.dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
const importDialog = await import("../dialogs/import.js"); const importService = await import("./import.js");
importDialog.uploadFiles(activeNote.noteId, files, { importService.uploadFiles(activeNote.noteId, files, {
safeImport: true, safeImport: true,
shrinkImages: true, shrinkImages: true,
textImportedAsText: true, textImportedAsText: true,
@@ -385,6 +385,8 @@ tabRow.addListener('tabRemove', async ({ detail }) => {
}); });
$(tabRow.el).on('contextmenu', '.note-tab', e => { $(tabRow.el).on('contextmenu', '.note-tab', e => {
e.preventDefault();
const tab = $(e.target).closest(".note-tab"); const tab = $(e.target).closest(".note-tab");
contextMenuService.initContextMenu(e, { contextMenuService.initContextMenu(e, {

View File

@@ -0,0 +1,292 @@
import server from "./server.js";
import linkService from "./link.js";
import utils from "./utils.js";
import treeCache from "./tree_cache.js";
import renderService from "./render.js";
import protectedSessionHolder from "./protected_session_holder.js";
import protectedSessionService from "./protected_session.js";
const MIN_ZOOM_LEVEL = 1;
const MAX_ZOOM_LEVEL = 6;
const ZOOMS = {
1: {
width: "100%",
height: "100%"
},
2: {
width: "49%",
height: "350px"
},
3: {
width: "32%",
height: "250px"
},
4: {
width: "24%",
height: "200px"
},
5: {
width: "19%",
height: "175px"
},
6: {
width: "16%",
height: "150px"
}
};
class NoteDetailBook {
/**
* @param {TabContext} ctx
*/
constructor(ctx) {
this.ctx = ctx;
this.$component = ctx.$tabContent.find('.note-detail-book');
this.$content = this.$component.find('.note-detail-book-content');
this.$zoomInButton = this.$component.find('.book-zoom-in-button');
this.$zoomOutButton = this.$component.find('.book-zoom-out-button');
this.$expandChildrenButton = this.$component.find('.expand-children-button');
this.$zoomInButton.click(() => this.setZoom(this.zoomLevel - 1));
this.$zoomOutButton.click(() => this.setZoom(this.zoomLevel + 1));
this.$expandChildrenButton.click(async () => {
for (let i = 1; i < 30; i++) { // protection against infinite cycle
const $unexpandedLinks = this.$content.find('.note-book-open-children-button:visible');
if ($unexpandedLinks.length === 0) {
break;
}
for (const link of $unexpandedLinks) {
const $card = $(link).closest(".note-book-card");
await this.expandCard($card);
}
}
});
this.$content.on('click', '.note-book-open-children-button', async ev => {
const $card = $(ev.target).closest('.note-book-card');
await this.expandCard($card);
});
this.$content.on('click', '.note-book-hide-children-button', async ev => {
const $card = $(ev.target).closest('.note-book-card');
$card.find('.note-book-open-children-button').show();
$card.find('.note-book-hide-children-button').hide();
$card.find('.note-book-children-content').empty();
});
}
async expandCard($card) {
const noteId = $card.attr('data-note-id');
const note = await treeCache.getNote(noteId);
$card.find('.note-book-open-children-button').hide();
$card.find('.note-book-hide-children-button').show();
await this.renderIntoElement(note, $card.find('.note-book-children-content'));
}
setZoom(zoomLevel) {
if (!(zoomLevel in ZOOMS)) {
zoomLevel = this.getDefaultZoomLevel();
}
this.zoomLevel = zoomLevel;
this.$zoomInButton.prop("disabled", zoomLevel === MIN_ZOOM_LEVEL);
this.$zoomOutButton.prop("disabled", zoomLevel === MAX_ZOOM_LEVEL);
this.$content.find('.note-book-card').css("flex-basis", ZOOMS[zoomLevel].width);
this.$content.find('.note-book-content').css("max-height", ZOOMS[zoomLevel].height);
}
async render() {
this.$content.empty();
if (this.isAutoBook()) {
const $addTextLink = $('<a href="javascript:">here</a>').click(() => {
this.ctx.renderComponent(true);
});
this.$content.append($('<div class="note-book-auto-message"></div>')
.append(`This note doesn't have any content so we display its children. Click `)
.append($addTextLink)
.append(' if you want to add some text.'))
}
const zoomLevel = parseInt(await this.ctx.note.getLabelValue('bookZoomLevel')) || this.getDefaultZoomLevel();
this.setZoom(zoomLevel);
await this.renderIntoElement(this.ctx.note, this.$content);
}
async renderIntoElement(note, $container) {
for (const childNote of await note.getChildNotes()) {
const type = this.getRenderingType(childNote);
const $card = $('<div class="note-book-card">')
.attr('data-note-id', childNote.noteId)
.css("flex-basis", ZOOMS[this.zoomLevel].width)
.addClass("type-" + type)
.append($('<h5 class="note-book-title">').append(await linkService.createNoteLink(childNote.noteId, null, false)))
.append($('<div class="note-book-content">')
.css("max-height", ZOOMS[this.zoomLevel].height)
.append(await this.getNoteContent(type, childNote)));
const childCount = childNote.getChildNoteIds().length;
if (childCount > 0) {
const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`;
$card.append($('<div class="note-book-children">')
.append($(`<a class="note-book-open-children-button" href="javascript:">+ Show ${label}</a>`))
.append($(`<a class="note-book-hide-children-button" href="javascript:">- Hide ${label}</a>`).hide())
.append($('<div class="note-book-children-content">'))
);
}
$container.append($card);
}
}
async getNoteContent(type, note) {
if (type === 'text') {
const fullNote = await server.get('notes/' + note.noteId);
const $content = $("<div>").html(fullNote.content);
if (utils.isHtmlEmpty(fullNote.content)) {
return "";
}
else {
return $content;
}
}
else if (type === 'code') {
const fullNote = await server.get('notes/' + note.noteId);
if (fullNote.content.trim() === "") {
return "";
}
return $("<pre>").text(fullNote.content);
}
else if (type === 'image') {
return $("<img>").attr("src", `api/images/${note.noteId}/${note.title}`);
}
else if (type === 'file') {
function getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol
return utils.getHost() + "/api/notes/" + note.noteId + "/download";
}
const $downloadButton = $('<button class="file-download btn btn-primary" type="button">Download</button>');
const $openButton = $('<button class="file-open btn btn-primary" type="button">Open</button>');
$downloadButton.click(() => utils.download(getFileUrl()));
$openButton.click(() => {
if (utils.isElectron()) {
const open = require("open");
open(getFileUrl());
}
else {
window.location.href = getFileUrl();
}
});
// open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!note.isProtected);
return $('<div>')
.append($downloadButton)
.append(' &nbsp; ')
.append($openButton);
}
else if (type === 'render') {
const $el = $('<div>');
await renderService.render(note, $el, this.ctx);
return $el;
}
else if (type === 'protected-session') {
const $button = $(`<button class="btn btn-sm"><span class="jam jam-door"></span> Enter protected session</button>`)
.click(protectedSessionService.enterProtectedSession);
return $("<div>")
.append("<div>This note is protected and to access it you need to enter password.</div>")
.append("<br/>")
.append($button);
}
else {
return "<em>Content of this note cannot be displayed in the book format</em>";
}
}
/** @return {boolean} true if this is "auto book" activated (empty text note) and not explicit book note */
isAutoBook() {
return this.ctx.note.type !== 'book';
}
getDefaultZoomLevel() {
if (this.isAutoBook()) {
const w = this.$component.width();
if (w <= 600) {
return 1;
} else if (w <= 900) {
return 2;
} else if (w <= 1300) {
return 3;
} else {
return 4;
}
}
else {
return 1;
}
}
getRenderingType(childNote) {
let type = childNote.type;
if (childNote.isProtected) {
if (protectedSessionHolder.isProtectedSessionAvailable()) {
protectedSessionHolder.touchProtectedSession();
}
else {
type = 'protected-session';
}
}
return type;
}
getContent() {}
show() {
this.$component.show();
}
focus() {}
onNoteChange() {}
cleanup() {
this.$content.empty();
}
scrollToTop() {
this.$component.scrollTop(0);
}
}
export default NoteDetailBook;

View File

@@ -1,5 +1,4 @@
import bundleService from "./bundle.js"; import renderService from "./render.js";
import server from "./server.js";
class NoteDetailRender { class NoteDetailRender {
/** /**
@@ -16,29 +15,10 @@ class NoteDetailRender {
} }
async render() { async render() {
const attributes = await this.ctx.attributes.getAttributes();
const renderNotes = attributes.filter(attr =>
attr.type === 'relation'
&& attr.name === 'renderNote'
&& !!attr.value);
this.$component.show(); this.$component.show();
this.$noteDetailRenderHelp.hide();
this.$noteDetailRenderContent.empty(); await renderService.render(this.ctx.note, this.$noteDetailRenderContent, this.ctx);
this.$noteDetailRenderContent.toggle(renderNotes.length > 0);
this.$noteDetailRenderHelp.toggle(renderNotes.length === 0);
for (const renderNote of renderNotes) {
const bundle = await server.get('script/bundle/' + renderNote.value);
this.$noteDetailRenderContent.append(bundle.html);
const $result = await bundleService.executeBundle(bundle, this.ctx.note, this.ctx);
if ($result) {
this.$noteDetailRenderContent.append($result);
}
}
} }
getContent() {} getContent() {}

View File

@@ -11,6 +11,7 @@ const NOTE_TYPES = [
{ type: "text", mime: "text/html", title: "Text", selectable: true }, { type: "text", mime: "text/html", title: "Text", selectable: true },
{ type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true }, { type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true },
{ type: "render", mime: '', title: "Render Note", selectable: true }, { type: "render", mime: '', title: "Render Note", selectable: true },
{ type: "book", mime: '', title: "Book", selectable: true },
{ type: "code", mime: 'text/plain', title: "Code", selectable: true } { type: "code", mime: 'text/plain', title: "Code", selectable: true }
]; ];

View File

@@ -51,7 +51,11 @@ function reloadOptions() {
return optionsReady; return optionsReady;
} }
/** just waits for some options without triggering reload */ /**
* just waits for some options without triggering reload
*
* @return {Options}
*/
async function waitForOptions() { async function waitForOptions() {
return await optionsReady; return await optionsReady;
} }

View File

@@ -46,8 +46,7 @@ async function setupProtectedSession(password) {
await treeService.reload(); await treeService.reload();
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for children overview) // it's important that tree has been already reloaded at this point since detail also uses tree cache (for book)
// children overview is the reason why we need to reload all tabs
await noteDetailService.reloadAllTabs(); await noteDetailService.reloadAllTabs();
if (protectedSessionDeferred !== null) { if (protectedSessionDeferred !== null) {

View File

@@ -0,0 +1,33 @@
import server from "./server.js";
import bundleService from "./bundle.js";
async function render(note, $el, ctx) {
const attributes = await note.getAttributes();
const renderNoteIds = attributes.filter(attr =>
attr.type === 'relation'
&& attr.name === 'renderNote'
&& !!attr.value).map(rel => rel.value);
$el.empty().toggle(renderNoteIds.length > 0);
for (const renderNoteId of renderNoteIds) {
const bundle = await server.get('script/bundle/' + renderNoteId);
const $scriptContainer = $('<div>');
$el.append($scriptContainer);
$scriptContainer.append(bundle.html);
const $result = await bundleService.executeBundle(bundle, note, ctx, $scriptContainer);
if ($result) {
$scriptContainer.append($result);
}
}
return renderNoteIds.length > 0;
}
export default {
render
}

View File

@@ -2,7 +2,7 @@ import FrontendScriptApi from './frontend_script_api.js';
import utils from './utils.js'; import utils from './utils.js';
import treeCache from './tree_cache.js'; import treeCache from './tree_cache.js';
async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabContext = null) { async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabContext = null, $container = null) {
const modules = {}; const modules = {};
const startNote = await treeCache.getNote(startNoteId); const startNote = await treeCache.getNote(startNoteId);
@@ -11,7 +11,7 @@ async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabCo
return { return {
modules: modules, modules: modules,
notes: utils.toObject(allNotes, note => [note.noteId, note]), notes: utils.toObject(allNotes, note => [note.noteId, note]),
apis: utils.toObject(allNotes, note => [note.noteId, new FrontendScriptApi(startNote, note, originEntity, tabContext)]), apis: utils.toObject(allNotes, note => [note.noteId, new FrontendScriptApi(startNote, note, originEntity, tabContext, $container)]),
require: moduleNoteIds => { require: moduleNoteIds => {
return moduleName => { return moduleName => {
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId)); const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));

View File

@@ -0,0 +1,48 @@
import optionsService from "./options.js";
export async function initSpellCheck() {
const options = await optionsService.waitForOptions();
if (!options.is('spellCheckEnabled')) {
return;
}
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
const {remote, shell} = require('electron');
const spellCheckHandler = new SpellCheckHandler();
spellCheckHandler.attachToInput();
spellCheckHandler.switchLanguage(options.get('spellCheckLanguageCode'));
spellCheckHandler.currentSpellcheckerChanged.subscribe(() => {
console.debug(`Detected language is ${spellCheckHandler.currentSpellcheckerLanguage}`);
spellCheckHandler.currentSpellchecker.add("trilium");
spellCheckHandler.currentSpellchecker.add("https");
spellCheckHandler.currentSpellchecker.add("github");
spellCheckHandler.currentSpellchecker.add("unordered");
});
const contextMenuBuilder = new ContextMenuBuilder(spellCheckHandler, null, true, (menu, menuInfo) => {
// There's no menu.remove(id) so this is a convoluted way of removing the 'Search with Google' menu item
const oldItems = menu.items;
menu.clear();
oldItems.forEach(oldItem => {
if (!oldItem.label.includes('Google')) {
menu.append(oldItem);
} else {
menu.append(new remote.MenuItem({
label: 'Search with DuckDuckGo',
click: () => {
shell.openExternal(`https://duckduckgo.com/?q=${encodeURIComponent(menuInfo.selectionText)}`);
}
}));
}
});
});
new ContextMenuListener(async (info) => {
await contextMenuBuilder.showPopupMenu(info);
});
}

View File

@@ -23,7 +23,8 @@ const componentClasses = {
'search': "./note_detail_search.js", 'search': "./note_detail_search.js",
'render': "./note_detail_render.js", 'render': "./note_detail_render.js",
'relation-map': "./note_detail_relation_map.js", 'relation-map': "./note_detail_relation_map.js",
'protected-session': "./note_detail_protected_session.js" 'protected-session': "./note_detail_protected_session.js",
'book': "./note_detail_book.js"
}; };
let showSidebarInNewTab = true; let showSidebarInNewTab = true;
@@ -64,7 +65,6 @@ class TabContext {
this.$notePathList = this.$tabContent.find(".note-path-list"); this.$notePathList = this.$tabContent.find(".note-path-list");
this.$notePathCount = this.$tabContent.find(".note-path-count"); this.$notePathCount = this.$tabContent.find(".note-path-count");
this.$noteDetailComponents = this.$tabContent.find(".note-detail-component"); this.$noteDetailComponents = this.$tabContent.find(".note-detail-component");
this.$childrenOverview = this.$tabContent.find(".children-overview");
this.$scriptArea = this.$tabContent.find(".note-detail-script-area"); this.$scriptArea = this.$tabContent.find(".note-detail-script-area");
this.$savedIndicator = this.$tabContent.find(".saved-indicator"); this.$savedIndicator = this.$tabContent.find(".saved-indicator");
this.noteChangeDisabled = false; this.noteChangeDisabled = false;
@@ -115,13 +115,13 @@ class TabContext {
await this.initComponent(); await this.initComponent();
} }
async initComponent() { async initComponent(disableAutoBook = false) {
const type = this.getComponentType(); this.type = this.getComponentType(disableAutoBook);
if (!(type in this.components)) { if (!(this.type in this.components)) {
const clazz = await import(componentClasses[type]); const clazz = await import(componentClasses[this.type]);
this.components[type] = new clazz.default(this); this.components[this.type] = new clazz.default(this);
} }
} }
@@ -163,7 +163,7 @@ class TabContext {
this.setTitleBar(); this.setTitleBar();
this.closeAutocomplete(); // esp. on windows autocomplete is not getting closed automatically this.cleanup(); // esp. on windows autocomplete is not getting closed automatically
setTimeout(async () => { setTimeout(async () => {
// we include the note into recent list only if the user stayed on the note at least 5 seconds // we include the note into recent list only if the user stayed on the note at least 5 seconds
@@ -179,8 +179,6 @@ class TabContext {
if (utils.isDesktop()) { if (utils.isDesktop()) {
this.noteType.update(); this.noteType.update();
this.showChildrenOverview();
} }
if (this.sidebar) { if (this.sidebar) {
@@ -210,11 +208,11 @@ class TabContext {
this.setTitleBar(); this.setTitleBar();
} }
async renderComponent() { async renderComponent(disableAutoBook = false) {
await this.initComponent(); await this.initComponent(disableAutoBook);
for (const componentType in this.components) { for (const componentType in this.components) {
if (componentType !== this.getComponentType()) { if (componentType !== this.type) {
this.components[componentType].cleanup(); this.components[componentType].cleanup();
} }
} }
@@ -283,30 +281,31 @@ class TabContext {
} }
getComponent() { getComponent() {
const type = this.getComponentType(); return this.components[this.type];
return this.components[type];
} }
getComponentType() { getComponentType(disableAutoBook) {
let type; if (!this.note) {
return "empty";
if (this.note) {
type = this.note.type;
if (this.note.isProtected) {
if (protectedSessionHolder.isProtectedSessionAvailable()) {
protectedSessionHolder.touchProtectedSession();
} else {
type = 'protected-session';
// user shouldn't be able to edit note title
this.$noteTitle.prop("readonly", true);
}
}
} else {
type = 'empty';
} }
let type = this.note.type;
if (type === 'text' && !disableAutoBook && utils.isHtmlEmpty(this.note.content) && this.note.hasChildren()) {
type = 'book';
}
if (this.note.isProtected) {
if (protectedSessionHolder.isProtectedSessionAvailable()) {
protectedSessionHolder.touchProtectedSession();
} else {
type = 'protected-session';
// user shouldn't be able to edit note title
this.$noteTitle.prop("readonly", true);
}
}
return type; return type;
} }
@@ -365,33 +364,6 @@ class TabContext {
this.$savedIndicator.fadeOut(); this.$savedIndicator.fadeOut();
} }
async showChildrenOverview() {
const attributes = await this.attributes.getAttributes();
const hideChildrenOverview = attributes.some(attr => attr.type === 'label' && attr.name === 'hideChildrenOverview')
|| this.note.type === 'relation-map'
|| this.note.type === 'image'
|| this.note.type === 'file';
if (hideChildrenOverview) {
this.$childrenOverview.hide();
return;
}
this.$childrenOverview.empty();
for (const childBranch of await this.note.getChildBranches()) {
const link = $('<a>', {
href: 'javascript:',
text: await treeUtils.getNoteTitle(childBranch.noteId, childBranch.parentNoteId)
}).attr('data-action', 'note').attr('data-note-path', this.notePath + '/' + childBranch.noteId);
const childEl = $('<div class="child-overview-item">').html(link);
this.$childrenOverview.append(childEl);
}
this.$childrenOverview.show();
}
async addPath(notePath, isCurrent) { async addPath(notePath, isCurrent) {
const title = await treeUtils.getNotePathTitle(notePath); const title = await treeUtils.getNotePathTitle(notePath);
@@ -440,15 +412,17 @@ class TabContext {
async remove() { async remove() {
// sometimes there are orphan autocompletes after closing the tab // sometimes there are orphan autocompletes after closing the tab
this.closeAutocomplete(); this.cleanup();
await this.saveNoteIfChanged(); await this.saveNoteIfChanged();
this.$tabContent.remove(); this.$tabContent.remove();
} }
closeAutocomplete() { cleanup() {
if (utils.isDesktop()) { if (this.$tabContent && utils.isDesktop()) {
this.$tabContent.find('.aa-input').autocomplete('close'); this.$tabContent.find('.aa-input').autocomplete('close');
$('.note-tooltip').remove();
} }
} }

View File

@@ -31,6 +31,16 @@ async function prepareBranch(note) {
} }
} }
const NOTE_TYPE_ICONS = {
"file": "jam jam-attachment",
"image": "jam jam-picture",
"code": "jam jam-terminal",
"render": "jam jam-play",
"search": "jam jam-search-folder",
"relation-map": "jam jam-map",
"book": "jam jam-book"
};
async function getIcon(note) { async function getIcon(note) {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId(); const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
@@ -48,23 +58,8 @@ async function getIcon(note) {
return "jam jam-file"; return "jam jam-file";
} }
} }
else if (note.type === 'file') { else {
return "jam jam-attachment" return NOTE_TYPE_ICONS[note.type];
}
else if (note.type === 'image') {
return "jam jam-picture"
}
else if (note.type === 'code') {
return "jam jam-terminal"
}
else if (note.type === 'render') {
return "jam jam-play"
}
else if (note.type === 'search') {
return "jam jam-search-folder"
}
else if (note.type === 'relation-map') {
return "jam jam-map"
} }
} }
@@ -161,6 +156,10 @@ async function getExtraClasses(note) {
extraClasses.push(utils.getMimeTypeClass(note.mime)); extraClasses.push(utils.getMimeTypeClass(note.mime));
} }
if (note.archived) {
extraClasses.push("archived");
}
return extraClasses.join(" "); return extraClasses.join(" ");
} }

View File

@@ -201,6 +201,10 @@ function closeActiveDialog() {
} }
} }
function isHtmlEmpty(html) {
return $("<div>").html(html).text().trim().length === 0 && !html.toLowerCase().includes('<img');
}
export default { export default {
reloadApp, reloadApp,
parseDate, parseDate,
@@ -231,5 +235,6 @@ export default {
getCookie, getCookie,
getNoteTypeClass, getNoteTypeClass,
getMimeTypeClass, getMimeTypeClass,
closeActiveDialog closeActiveDialog,
isHtmlEmpty
}; };

View File

@@ -1,5 +1,6 @@
import utils from './utils.js'; import utils from './utils.js';
import infoService from "./info.js"; import infoService from "./info.js";
import treeService from "./tree.js";
const $outstandingSyncsCount = $("#outstanding-syncs-count"); const $outstandingSyncsCount = $("#outstanding-syncs-count");

View File

@@ -20,7 +20,7 @@ class NoteRevisionsWidget extends StandardWidget {
const $showFullButton = $("<a>").append("show dialog").addClass('widget-header-action'); const $showFullButton = $("<a>").append("show dialog").addClass('widget-header-action');
$showFullButton.click(async () => { $showFullButton.click(async () => {
const attributesDialog = await import("../dialogs/note_revisions.js"); const attributesDialog = await import("../dialogs/note_revisions.js");
attributesDialog.showDialog(); attributesDialog.showCurrentNoteRevisions(this.ctx.note.noteId);
}); });
return [$showFullButton]; return [$showFullButton];

View File

@@ -31,11 +31,6 @@
font-weight: 600; font-weight: 600;
} }
.link-map-container .floating-button {
position: absolute !important;
z-index: 100;
}
.link-map-active-note { .link-map-active-note {
background-color: var(--accented-background-color) !important; background-color: var(--accented-background-color) !important;
} }

View File

@@ -75,9 +75,4 @@
.note-detail-relation-map .ui-contextmenu { .note-detail-relation-map .ui-contextmenu {
z-index: 100; z-index: 100;
}
.note-detail-relation-map .floating-button {
position: absolute !important;
z-index: 100;
} }

View File

@@ -108,7 +108,7 @@ ul.fancytree-container {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 200px; min-height: 500px;
overflow-wrap: break-word; /* otherwise CKEditor fails miserably on super long lines */ overflow-wrap: break-word; /* otherwise CKEditor fails miserably on super long lines */
font-family: var(--detail-font-family); font-family: var(--detail-font-family);
font-size: var(--detail-font-size); font-size: var(--detail-font-size);
@@ -136,7 +136,7 @@ ul.fancytree-container {
border: 0 !important; border: 0 !important;
box-shadow: none !important; box-shadow: none !important;
/* This is because with empty content height of editor is 0 and it's impossible to click into it */ /* This is because with empty content height of editor is 0 and it's impossible to click into it */
min-height: 200px; min-height: 500px;
} }
.note-detail-text p:first-child, .note-detail-text::before { .note-detail-text p:first-child, .note-detail-text::before {
@@ -213,6 +213,10 @@ span.fancytree-node:hover span.fancytree-title {
border-radius: 5px; border-radius: 5px;
} }
span.fancytree-node.archived {
opacity: 0.6;
}
.ui-autocomplete { .ui-autocomplete {
max-height: 300px; max-height: 300px;
overflow-y: auto; overflow-y: auto;
@@ -353,11 +357,11 @@ div.ui-tooltip {
} }
.note-detail-code-editor { .note-detail-code-editor {
min-height: 200px; min-height: 500px;
} }
.note-detail-render { .note-detail-render {
min-height: 200px; min-height: 500px;
} }
.CodeMirror { .CodeMirror {
@@ -367,7 +371,7 @@ div.ui-tooltip {
} }
.CodeMirror-scroll { .CodeMirror-scroll {
min-height: 200px; min-height: 500px;
} }
.CodeMirror-gutters { .CodeMirror-gutters {
@@ -390,37 +394,6 @@ div.ui-tooltip {
font-size: larger; font-size: larger;
} }
.children-overview {
flex-grow: 1000;
flex-shrink: 1000;
flex-basis: 0;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
height: 110px;
overflow: auto;
}
.child-overview-item {
font-weight: bold;
padding: 10px;
background: var(--accented-background-color);
width: 150px;
height: 85px;
line-height: 2em;
margin-right: 20px;
border-radius: 15px;
overflow: hidden;
text-align: center;
margin-top: 15px;
text-overflow: ellipsis;
overflow-wrap: break-word;
}
.child-overview-item a {
color: var(--muted-text-color);
}
#sql-console-query { #sql-console-query {
height: 150px; height: 150px;
width: 100%; width: 100%;
@@ -817,4 +790,71 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.modal-header { .modal-header {
padding: 0.7rem 1rem !important; /* make modal header padding slightly smaller */ padding: 0.7rem 1rem !important; /* make modal header padding slightly smaller */
}
.floating-button {
position: absolute !important;
z-index: 100;
}
.note-detail-book {
height: 100%;
}
.note-detail-book-content {
display: flex;
flex-wrap: wrap;
overflow: auto;
height: 100%;
align-content: start;
}
.note-book-card {
border-radius: 10px;
background-color: var(--accented-background-color);
padding: 15px;
padding-bottom: 5px;
margin: 5px;
margin-left: 0;
overflow: hidden;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.note-book-card .note-book-card {
border: 1px solid var(--main-border-color);
}
.note-book-content {
overflow: hidden;
}
.note-book-card.type-image .note-book-content, .note-book-card.type-file .note-book-content, .note-book-card.type-protected-session .note-book-content {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.note-book-card.type-image .note-book-content img {
max-width: 100%;
max-height: 100%;
}
.note-book-title {
flex-grow: 0;
}
.note-book-content {
flex-grow: 1;
}
.note-book-auto-message {
background-color: var(--accented-background-color);
text-align: center;
width: 100%;
border-radius: 10px;
padding: 5px;
margin-top: 5px;
} }

View File

@@ -9,7 +9,7 @@
--main-background-color: white; --main-background-color: white;
--main-text-color: black; --main-text-color: black;
--main-border-color: #ccc; --main-border-color: #ccc;
--accented-background-color: #eee; --accented-background-color: #f5f5f5;
--more-accented-background-color: #ccc; --more-accented-background-color: #ccc;
--header-background-color: #f8f8f8; --header-background-color: #f8f8f8;
--button-background-color: #eee; --button-background-color: #eee;
@@ -183,6 +183,8 @@ body {
/* todo lists */ /* todo lists */
--ck-color-todo-list-checkmark-border: var(--main-border-color); --ck-color-todo-list-checkmark-border: var(--main-border-color);
--ck-color-engine-placeholder-text: var(--main-text-color);
} }
body { body {

View File

@@ -13,7 +13,7 @@ const ImportContext = require('../../services/import_context');
async function importToBranch(req) { async function importToBranch(req) {
const {parentNoteId} = req.params; const {parentNoteId} = req.params;
const {importId} = req.body; const {importId, last} = req.body;
const options = { const options = {
safeImport: req.body.safeImport !== 'false', safeImport: req.body.safeImport !== 'false',
@@ -65,6 +65,11 @@ async function importToBranch(req) {
return [500, message]; return [500, message];
} }
if (last === "true") {
// small timeout to avoid race condition (message is received before the transaction is committed)
setTimeout(() => importContext.importSucceeded(parentNoteId, note.noteId), 1000);
}
// import has deactivated note events so note cache is not updated // import has deactivated note events so note cache is not updated
// instead we force it to reload (can be async) // instead we force it to reload (can be async)
noteCacheService.load(); noteCacheService.load();

View File

@@ -32,7 +32,9 @@ const ALLOWED_OPTIONS = [
'similarNotesWidget', 'similarNotesWidget',
'editedNotesWidget', 'editedNotesWidget',
'calendarWidget', 'calendarWidget',
'codeNotesMimeTypes' 'codeNotesMimeTypes',
'spellCheckEnabled',
'spellCheckLanguageCode'
]; ];
async function getOptions() { async function getOptions() {

View File

@@ -75,6 +75,7 @@ async function forceNoteSync(req) {
const noteId = req.params.noteId; const noteId = req.params.noteId;
await syncTableService.addNoteSync(noteId); await syncTableService.addNoteSync(noteId);
await syncTableService.addNoteContentSync(noteId);
for (const branchId of await sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 0 AND noteId = ?", [noteId])) { for (const branchId of await sql.getColumn("SELECT branchId FROM branches WHERE isDeleted = 0 AND noteId = ?", [noteId])) {
await syncTableService.addBranchSync(branchId); await syncTableService.addBranchSync(branchId);

View File

@@ -3,6 +3,7 @@
const sql = require('../../services/sql'); const sql = require('../../services/sql');
const optionService = require('../../services/options'); const optionService = require('../../services/options');
const protectedSessionService = require('../../services/protected_session'); const protectedSessionService = require('../../services/protected_session');
const noteCacheService = require('../../services/note_cache');
async function getNotes(noteIds) { async function getNotes(noteIds) {
const notes = await sql.getManyRows(` const notes = await sql.getManyRows(`
@@ -31,7 +32,11 @@ async function getNotes(noteIds) {
protectedSessionService.decryptNotes(notes); protectedSessionService.decryptNotes(notes);
notes.forEach(note => note.isProtected = !!note.isProtected); notes.forEach(note => {
note.isProtected = !!note.isProtected;
note.archived = noteCacheService.isArchived(note.noteId)
});
return notes; return notes;
} }

View File

@@ -4,7 +4,7 @@ const build = require('./build');
const packageJson = require('../../package'); const packageJson = require('../../package');
const {TRILIUM_DATA_DIR} = require('./data_dir'); const {TRILIUM_DATA_DIR} = require('./data_dir');
const APP_DB_VERSION = 145; const APP_DB_VERSION = 146;
const SYNC_VERSION = 10; const SYNC_VERSION = 10;
const CLIPPER_PROTOCOL_VERSION = "1.0"; const CLIPPER_PROTOCOL_VERSION = "1.0";

View File

@@ -17,12 +17,12 @@ const BUILTIN_ATTRIBUTES = [
{ type: 'label', name: 'disableInclusion' }, { type: 'label', name: 'disableInclusion' },
{ type: 'label', name: 'appCss' }, { type: 'label', name: 'appCss' },
{ type: 'label', name: 'appTheme' }, { type: 'label', name: 'appTheme' },
{ type: 'label', name: 'hideChildrenOverview' },
{ type: 'label', name: 'hidePromotedAttributes' }, { type: 'label', name: 'hidePromotedAttributes' },
{ type: 'label', name: 'readOnly' }, { type: 'label', name: 'readOnly' },
{ type: 'label', name: 'run', isDangerous: true }, { type: 'label', name: 'run', isDangerous: true },
{ type: 'label', name: 'customRequestHandler', isDangerous: true }, { type: 'label', name: 'customRequestHandler', isDangerous: true },
{ type: 'label', name: 'customResourceProvider', isDangerous: true }, { type: 'label', name: 'customResourceProvider', isDangerous: true },
{ type: 'label', name: 'bookZoomLevel', isDangerous: false },
// relation names // relation names
{ type: 'relation', name: 'runOnNoteView', isDangerous: true }, { type: 'relation', name: 'runOnNoteView', isDangerous: true },

View File

@@ -1 +1 @@
module.exports = { buildDate:"2019-10-09T23:09:38+02:00", buildRevision: "6c3809e1db71ebca7bf0ca69f664c3c3f1af793a" }; module.exports = { buildDate:"2019-10-15T20:42:17+02:00", buildRevision: "2be1aca2f3a5912c0b1347bc4ebdce6bff999018" };

View File

@@ -216,7 +216,7 @@ async function findLogicIssues() {
FROM notes FROM notes
WHERE WHERE
isDeleted = 0 isDeleted = 0
AND type NOT IN ('text', 'code', 'render', 'file', 'image', 'search', 'relation-map')`, AND type NOT IN ('text', 'code', 'render', 'file', 'image', 'search', 'relation-map', 'book')`,
({noteId, type}) => `Note ${noteId} has invalid type=${type}`); ({noteId, type}) => `Note ${noteId} has invalid type=${type}`);
await findIssues(` await findIssues(`

View File

@@ -64,6 +64,7 @@ const EXTENSION_TO_MIME = {
".swift": "text/x-swift" ".swift": "text/x-swift"
}; };
/** @returns false if MIME is not detected */
function getMime(fileName) { function getMime(fileName) {
if (fileName.toLowerCase() === 'dockerfile') { if (fileName.toLowerCase() === 'dockerfile') {
return "text/x-dockerfile"; return "text/x-dockerfile";
@@ -79,7 +80,7 @@ function getMime(fileName) {
} }
function getType(importContext, mime) { function getType(importContext, mime) {
mime = mime.toLowerCase(); mime = mime ? mime.toLowerCase() : '';
if (importContext.textImportedAsText && (mime === 'text/html' || ['text/markdown', 'text/x-markdown'].includes(mime))) { if (importContext.textImportedAsText && (mime === 'text/html' || ['text/markdown', 'text/x-markdown'].includes(mime))) {
return 'text'; return 'text';
@@ -96,7 +97,7 @@ function getType(importContext, mime) {
} }
function normalizeMimeType(mime) { function normalizeMimeType(mime) {
mime = mime.toLowerCase(); mime = mime ? mime.toLowerCase() : '';
if (!(mime in CODE_MIME_TYPES) || CODE_MIME_TYPES[mime] === true) { if (!(mime in CODE_MIME_TYPES) || CODE_MIME_TYPES[mime] === true) {
return mime; return mime;

View File

@@ -8,7 +8,7 @@ const path = require('path');
const mimeService = require('./mime'); const mimeService = require('./mime');
async function importSingleFile(importContext, file, parentNote) { async function importSingleFile(importContext, file, parentNote) {
const mime = mimeService.getMime(file.originalname); const mime = mimeService.getMime(file.originalname) || file.mimetype;
if (importContext.textImportedAsText) { if (importContext.textImportedAsText) {
if (mime === 'text/html') { if (mime === 'text/html') {
@@ -47,7 +47,7 @@ async function importFile(importContext, file, parentNote) {
target: 'into', target: 'into',
isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(), isProtected: parentNote.isProtected && protectedSessionService.isProtectedSessionAvailable(),
type: 'file', type: 'file',
mime: mimeService.getMime(originalName), mime: mimeService.getMime(originalName) || file.mimetype,
attributes: [ attributes: [
{ type: "label", name: "originalFileName", value: originalName }, { type: "label", name: "originalFileName", value: originalName },
{ type: "label", name: "fileSize", value: size } { type: "label", name: "fileSize", value: size }
@@ -62,7 +62,7 @@ async function importFile(importContext, file, parentNote) {
async function importCodeNote(importContext, file, parentNote) { async function importCodeNote(importContext, file, parentNote) {
const title = getFileNameWithoutExtension(file.originalname); const title = getFileNameWithoutExtension(file.originalname);
const content = file.buffer.toString("UTF-8"); const content = file.buffer.toString("UTF-8");
const detectedMime = mimeService.getMime(file.originalname); const detectedMime = mimeService.getMime(file.originalname) || file.mimetype;
const mime = mimeService.normalizeMimeType(detectedMime); const mime = mimeService.normalizeMimeType(detectedMime);
const {note} = await noteService.createNote(parentNote.noteId, title, content, { const {note} = await noteService.createNote(parentNote.noteId, title, content, {

View File

@@ -14,6 +14,7 @@ const commonmark = require('commonmark');
const ImportContext = require('../import_context'); const ImportContext = require('../import_context');
const protectedSessionService = require('../protected_session'); const protectedSessionService = require('../protected_session');
const mimeService = require("./mime"); const mimeService = require("./mime");
const treeService = require("../tree");
/** /**
* @param {ImportContext} importContext * @param {ImportContext} importContext
@@ -115,11 +116,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
function getNoteId(noteMeta, filePath) { function getNoteId(noteMeta, filePath) {
const filePathNoExt = getTextFileWithoutExtension(filePath); const filePathNoExt = getTextFileWithoutExtension(filePath);
console.log(`Searching for noteId of filePath ${filePath} with meta: ${!!noteMeta}`);
if (filePathNoExt in createdPaths) { if (filePathNoExt in createdPaths) {
console.log("Found existing path", filePathNoExt, createdPaths[filePathNoExt]);
return createdPaths[filePathNoExt]; return createdPaths[filePathNoExt];
} }
@@ -131,7 +128,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
} }
function detectFileTypeAndMime(importContext, filePath) { function detectFileTypeAndMime(importContext, filePath) {
const mime = mimeService.getMime(filePath); const mime = mimeService.getMime(filePath) || "application/octet-stream";
const type = mimeService.getType(importContext, mime); const type = mimeService.getType(importContext, mime);
return { mime, type }; return { mime, type };
@@ -426,6 +423,12 @@ async function importTar(importContext, fileBuffer, importRootNote) {
for (const noteId in createdNoteIds) { // now the noteIds are unique for (const noteId in createdNoteIds) { // now the noteIds are unique
await noteService.scanForLinks(noteId); await noteService.scanForLinks(noteId);
if (!metaFile) {
// if there's no meta file then the notes are created based on the order in that tar file but that
// is usually quite random so we sort the notes in the way they would appear in the file manager
await treeService.sortNotesAlphabetically(noteId, true);
}
importContext.increaseProgressCount(); importContext.increaseProgressCount();
} }

View File

@@ -33,7 +33,7 @@ class ImportContext {
async increaseProgressCount() { async increaseProgressCount() {
this.progressCount++; this.progressCount++;
if (Date.now() - this.lastSentCountTs >= 500) { if (Date.now() - this.lastSentCountTs >= 1000) {
this.lastSentCountTs = Date.now(); this.lastSentCountTs = Date.now();
await ws.sendMessageToAllClients({ await ws.sendMessageToAllClients({
@@ -51,6 +51,15 @@ class ImportContext {
message: message message: message
}); });
} }
// must remaing non-static
async importSucceeded(parentNoteId, importedNoteId) {
await ws.sendMessageToAllClients({
type: 'import-succeeded',
parentNoteId: parentNoteId,
importedNoteId: importedNoteId
});
}
} }
module.exports = ImportContext; module.exports = ImportContext;

View File

@@ -86,9 +86,12 @@ async function findNotes(query) {
return []; return [];
} }
// trim is necessary because even with .split() trailing spaces are tokens which causes havoc const allTokens = query
// filtering '/' because it's used as separator .trim() // necessary because even with .split() trailing spaces are tokens which causes havoc
const allTokens = query.trim().toLowerCase().split(" ").filter(token => token !== '/'); .toLowerCase()
.split(/[ -]/)
.filter(token => token !== '/'); // '/' is used as separator
const tokens = allTokens.slice(); const tokens = allTokens.slice();
let results = []; let results = [];

View File

@@ -79,6 +79,9 @@ async function initNotSyncedOptions(initialized, startNotePath = 'root', opts =
await optionService.createOption('similarNotesWidget', '{"enabled":true,"expanded":true,"position":600}', false); await optionService.createOption('similarNotesWidget', '{"enabled":true,"expanded":true,"position":600}', false);
await optionService.createOption('initialized', initialized ? 'true' : 'false', false); await optionService.createOption('initialized', initialized ? 'true' : 'false', false);
await optionService.createOption('spellCheckEnabled', 'true', false);
await optionService.createOption('spellCheckLanguageCode', 'en-US', false);
} }
module.exports = { module.exports = {

View File

@@ -87,15 +87,28 @@ async function loadSubtreeNoteIds(parentNoteId, subtreeNoteIds) {
} }
} }
async function sortNotesAlphabetically(parentNoteId) { async function sortNotesAlphabetically(parentNoteId, directoriesFirst = false) {
await sql.transactional(async () => { await sql.transactional(async () => {
const notes = await sql.getRows(`SELECT branchId, noteId, title, isProtected const notes = await sql.getRows(
FROM notes JOIN branches USING(noteId) `SELECT branches.branchId, notes.noteId, title, isProtected,
WHERE branches.isDeleted = 0 AND parentNoteId = ?`, [parentNoteId]); CASE WHEN COUNT(childBranches.noteId) > 0 THEN 1 ELSE 0 END AS hasChildren
FROM notes
JOIN branches ON branches.noteId = notes.noteId
LEFT JOIN branches childBranches ON childBranches.parentNoteId = notes.noteId AND childBranches.isDeleted = 0
WHERE branches.isDeleted = 0 AND branches.parentNoteId = ?
GROUP BY notes.noteId`, [parentNoteId]);
protectedSessionService.decryptNotes(notes); protectedSessionService.decryptNotes(notes);
notes.sort((a, b) => a.title.toLowerCase() < b.title.toLowerCase() ? -1 : 1); notes.sort((a, b) => {
if (directoriesFirst && ((a.hasChildren && !b.hasChildren) || (!a.hasChildren && b.hasChildren))) {
// exactly one note of the two is a directory so the sorting will be done based on this status
return a.hasChildren ? -1 : 1;
}
else {
return a.title.toLowerCase() < b.title.toLowerCase() ? -1 : 1;
}
});
let position = 1; let position = 1;

View File

@@ -0,0 +1,17 @@
<div class="note-detail-book note-detail-component">
<div class="btn-group floating-button" style="right: 20px; top: 20px;">
<button type="button"
class="expand-children-button btn icon-button jam jam-arrows-v"
title="Expand all children"></button>
<button type="button"
class="book-zoom-in-button btn icon-button jam jam-search-plus"
title="Zoom In"></button>
<button type="button"
class="book-zoom-out-button btn icon-button jam jam-search-minus"
title="Zoom Out"></button>
</div>
<div class="note-detail-book-content"></div>
</div>

View File

@@ -22,7 +22,7 @@
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-html" <input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-html"
value="html"> value="html">
<label class="form-check-label" for="export-subtree-format-html">HTML in TAR archiv - this is recommended since this preserves all the formatting.</label> <label class="form-check-label" for="export-subtree-format-html">HTML in TAR archive - this is recommended since this preserves all the formatting.</label>
</div> </div>
<div class="form-check"> <div class="form-check">

View File

@@ -9,10 +9,6 @@
</div> </div>
<form id="import-form"> <form id="import-form">
<div class="modal-body"> <div class="modal-body">
<div id="import-progress-count-wrapper" class="alert alert-primary" style="padding: 15px;">
<strong>Note import progress count:</strong> <span id="import-progress-count"></span>
</div>
<div class="form-group"> <div class="form-group">
<label for="import-file-upload-input"><strong>Choose import file</strong></label> <label for="import-file-upload-input"><strong>Choose import file</strong></label>

View File

@@ -22,15 +22,12 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-change-password">Change password</a> <a class="nav-link" data-toggle="tab" href="#options-change-password">Change password</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-protected-session">Protected session</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-note-revisions">Note revisions</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-sync-setup">Sync</a> <a class="nav-link" data-toggle="tab" href="#options-sync-setup">Sync</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-other">Other</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-advanced">Advanced</a> <a class="nav-link" data-toggle="tab" href="#options-advanced">Advanced</a>
</li> </li>
@@ -41,8 +38,7 @@
<% include options/sidebar.ejs %> <% include options/sidebar.ejs %>
<% include options/code_notes.ejs %> <% include options/code_notes.ejs %>
<% include options/change_password.ejs %> <% include options/change_password.ejs %>
<% include options/protected_session.ejs %> <% include options/other.ejs %>
<% include options/note_revisions.ejs %>
<% include options/sync.ejs %> <% include options/sync.ejs %>
<% include options/advanced.ejs %> <% include options/advanced.ejs %>
</div> </div>

View File

@@ -1,18 +0,0 @@
<div id="options-note-revisions" class="tab-pane">
<h4>Note revisions snapshot interval</h4>
<p>Note revision snapshot time interval is time in seconds after which new note revision will be created for the note.</p>
<form id="note-revision-snapshot-time-interval-form">
<div class="form-group">
<label for="note-revision-snapshot-time-interval-in-seconds">Note revision snapshot time interval (in seconds)</label>
<input class="form-control" id="note-revision-snapshot-time-interval-in-seconds" type="number">
</div>
<div style="display: flex; justify-content: space-between;">
<button class="btn btn-primary">Save</button>
<button class="btn btn-secondary" type="button" data-help-page="Note-revisions">Help</button>
</div>
</form>
</div>

View File

@@ -0,0 +1,44 @@
<div id="options-other" class="tab-pane">
<div>
<h4>Spell check</h4>
<p>These options apply only for desktop builds, browsers will use their own native spell check.</p>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="spell-check-enabled">
<label class="custom-control-label" for="spell-check-enabled">Enable spellcheck</label>
</div>
<br/>
<div class="form-group">
<label for="spell-check-language-code">Language code</label>
<input type="email" class="form-control" id="spell-check-language-code" placeholder="for example &quot;en-US&quot;, &quot;de-AT&quot;">
</div>
<p>Changes to the spell check options will take effect after application restart.</p>
</div>
<div>
<h4>Protected session timeout</h4>
<p>Protected session timeout is a time period after which the protected session is wiped out from
browser's memory. This is measured from the last interaction with protected notes. See <a href="https://github.com/zadam/trilium/wiki/Protected-notes" class="external">wiki</a> for more info.</p>
<div class="form-group">
<label for="protected-session-timeout-in-seconds">Protected session timeout (in seconds)</label>
<input class="form-control" id="protected-session-timeout-in-seconds" type="number">
</div>
</div>
<div>
<h4>Note revisions snapshot interval</h4>
<p>Note revision snapshot time interval is time in seconds after which new note revision will be created for the note. See <a href="https://github.com/zadam/trilium/wiki/Note-revisions" class="external">wiki</a> for more info.</p>
<div class="form-group">
<label for="note-revision-snapshot-time-interval-in-seconds">Note revision snapshot time interval (in seconds)</label>
<input class="form-control" id="note-revision-snapshot-time-interval-in-seconds" type="number">
</div>
</div>
</div>

View File

@@ -1,19 +0,0 @@
<div id="options-protected-session" class="tab-pane">
<h4>Protected session timeout</h4>
<p>Protected session timeout is a time period after which the protected session is wiped out from
browser's memory. This is measured from the last interaction with protected notes.</p>
<form id="protected-session-timeout-form">
<div class="form-group">
<label for="protected-session-timeout-in-seconds">Protected session timeout (in seconds)</label>
<input class="form-control" id="protected-session-timeout-in-seconds" type="number">
</div>
<div style="display: flex; justify-content: space-between;">
<button class="btn btn-primary">Save</button>
<button class="btn btn-secondary" type="button" data-help-page="Protected-notes">Help</button>
</div>
</form>
</div>

View File

@@ -34,7 +34,7 @@
<% include details/protected_session_password.ejs %> <% include details/protected_session_password.ejs %>
<div class="children-overview hide-toggle"></div> <% include details/book.ejs %>
</div> </div>
</div> </div>