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:
- before: nvm install 10 && nvm use 10
init: npm install
command: npm run start
command: npm run start-server
ports:
- port: 8080
onOpen: open-preview

View File

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

View File

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

View File

@@ -1,20 +1,26 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-linux-x64
rm -rf $BUILD_DIR
SRC_DIR=./dist/trilium-linux-x64-src
if [ "$1" != "DONTCOPY" ]
then
./bin/copy-trilium.sh $SRC_DIR
fi
echo "Copying required linux-x64 binaries"
rm -r node_modules/sqlite3/lib/binding/*
rm -r node_modules/pngquant-bin/vendor/*
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
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 bin/deps/linux-x64/image/pngquant node_modules/pngquant-bin/vendor/
cp -r bin/deps/linux-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
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 ...)
npm rebuild
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
./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
@@ -29,3 +35,7 @@ VERSION=`jq -r ".version" package.json`
cd dist
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
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
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
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
./bin/reset-local.sh
echo "Zipping mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -1,40 +1,32 @@
#!/usr/bin/env bash
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=12.10.0
NODE_VERSION=12.12.0
rm -r $PKG_DIR
mkdir $PKG_DIR
cd $PKG_DIR
if [ "$1" != "DONTCOPY" ]
then
./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
tar xvfJ 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 ..
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

View File

@@ -1,29 +1,38 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-windows-x64
rm -rf $BUILD_DIR
SRC_DIR=./dist/trilium-windows-x64-src
if [ "$1" != "DONTCOPY" ]
then
./bin/copy-trilium.sh $SRC_DIR
fi
echo "Copying required windows binaries"
rm -r node_modules/sqlite3/lib/binding/*
rm -r node_modules/mozjpeg/vendor/*
rm -r node_modules/pngquant-bin/vendor/*
rm -r node_modules/giflossy/vendor/*
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/win-x64/sqlite/* node_modules/sqlite3/lib/binding/
cp bin/deps/win-x64/image/cjpeg.exe node_modules/mozjpeg/vendor/
cp bin/deps/win-x64/image/pngquant.exe node_modules/pngquant-bin/vendor/
cp bin/deps/win-x64/image/gifsicle.exe node_modules/giflossy/vendor/
cp -r bin/deps/win-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/win-x64/image/cjpeg.exe $SRC_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/win-x64/image/pngquant.exe $SRC_DIR/node_modules/pngquant-bin/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
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
./bin/reset-local.sh
echo "Zipping windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`

View File

@@ -1,21 +1,23 @@
#!/usr/bin/env bash
rm -r node_modules
npm install
echo "Deleting existing builds"
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
bin/build-linux-x64.sh
# we'll just copy the same SRC dir to all the builds so we don't have to do npm install in each separately
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-debian.sh
bin/build-win-x64.sh DONTCOPY
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>
<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>
@@ -1533,7 +1533,7 @@ the backend.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -1997,7 +1997,7 @@ the backend.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -2765,7 +2765,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -3418,7 +3418,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -3596,7 +3596,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -3751,7 +3751,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -3901,7 +3901,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -4427,7 +4427,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -4560,7 +4560,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>
@@ -4935,7 +4935,7 @@ transactional by default.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#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>

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
*/
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();
return ret;
};
/**
@@ -343,7 +345,8 @@ function BackendScriptApi(currentNote, apiParams) {
this.getAppInfo = () => appInfo
}
module.exports = BackendScriptApi;</code></pre>
module.exports = BackendScriptApi;
</code></pre>
</article>
</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>
@@ -223,7 +333,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -336,7 +446,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -442,7 +552,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -552,7 +662,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -661,7 +771,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line33">line 33</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line36">line 36</a>
</li></ul></dd>
@@ -790,7 +900,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -945,7 +1055,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1100,7 +1210,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1280,7 +1390,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1413,7 +1523,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1519,7 +1629,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1625,7 +1735,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1784,7 +1894,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -1891,7 +2001,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2046,7 +2156,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2202,7 +2312,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2403,7 +2513,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2509,7 +2619,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2664,7 +2774,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -2773,7 +2883,7 @@ note.
<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#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>
@@ -2928,7 +3038,7 @@ note.
<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#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>
@@ -3061,7 +3171,7 @@ note.
<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#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>
@@ -3167,7 +3277,7 @@ note.
<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#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>
@@ -3255,7 +3365,7 @@ note.
<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#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>
@@ -3406,7 +3516,7 @@ note.
<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#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>
@@ -3539,7 +3649,7 @@ note.
<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#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>
@@ -3700,7 +3810,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -3860,7 +3970,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -4016,7 +4126,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -4167,7 +4277,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -4304,7 +4414,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>
@@ -4441,7 +4551,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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>

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>
<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>
@@ -93,7 +96,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -183,7 +186,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -241,7 +244,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -299,7 +302,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -357,7 +360,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -415,7 +418,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -473,7 +476,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -531,7 +534,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -679,7 +682,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -846,7 +849,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1020,7 +1023,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1126,7 +1129,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1228,7 +1231,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1330,7 +1333,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1432,7 +1435,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1583,7 +1586,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1750,7 +1753,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -1917,7 +1920,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2072,7 +2075,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2178,7 +2181,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2280,7 +2283,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2431,7 +2434,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2598,7 +2601,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2765,7 +2768,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -2920,7 +2923,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3090,7 +3093,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3241,7 +3244,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3351,7 +3354,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3525,7 +3528,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3631,7 +3634,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3782,7 +3785,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -3937,7 +3940,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -4048,7 +4051,7 @@ Cache is note instance scoped.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>
@@ -4132,7 +4135,7 @@ Cache is note instance scoped.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#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>

View File

@@ -35,6 +35,9 @@ const RELATION = 'relation';
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.
*/
class NoteShort {

View File

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

View File

@@ -44,9 +44,12 @@ import StandardWidget from '../widgets/standard_widget.js';
* @constructor
* @hideconstructor
*/
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) {
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
const $pluginButtons = $("#plugin-buttons");
/** @property {jQuery} container of all the rendered script content */
this.$container = $container;
/** @property {object} note where script started executing */
this.startNote = startNote;
/** @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
*/
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';
const electron = require('electron');
const {app, globalShortcut, BrowserWindow} = require('electron');
const path = require('path');
const log = require('./src/services/log');
const sqlInit = require('./src/services/sql_init');
@@ -10,10 +10,6 @@ const port = require('./src/services/port');
const env = require('./src/services/env');
const appIconService = require('./src/services/app_icon');
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
require('electron-debug')();
@@ -25,25 +21,25 @@ let mainWindow;
require('electron-dl')({ saveAs: true });
contextMenu({
menu: (actions, params, browserWindow) => [
actions.cut(),
actions.copy(),
actions.copyLink(),
actions.paste(),
{
label: 'Search DuckDuckGo for “{selection}”',
// Only show it when right-clicking text
visible: params.selectionText.trim().length > 0,
click: () => {
const {shell} = require('electron');
shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`);
}
},
actions.inspect()
]
});
// contextMenu({
// menu: (actions, params, browserWindow) => [
// actions.cut(),
// actions.copy(),
// actions.copyLink(),
// actions.paste(),
// {
// label: 'Search DuckDuckGo for “{selection}”',
// // Only show it when right-clicking text
// visible: params.selectionText.trim().length > 0,
// click: () => {
// const {shell} = require('electron');
//
// shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`);
// }
// },
// actions.inspect()
// ]
// });
function onClosed() {
// Dereference the window
@@ -66,7 +62,7 @@ async function createMainWindow() {
defaultHeight: 800
});
const win = new electron.BrowserWindow({
const win = new BrowserWindow({
x: mainWindowState.x,
y: mainWindowState.y,
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",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.35.2",
"version": "0.36.0-beta",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -17,8 +17,7 @@
"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-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",
"postinstall": "electron-builder install-app-deps"
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs"
},
"dependencies": {
"async-mutex": "0.1.4",
@@ -31,20 +30,20 @@
"dayjs": "1.8.16",
"debug": "4.1.1",
"ejs": "2.7.1",
"electron-context-menu": "0.15.0",
"electron-debug": "3.0.1",
"electron-dl": "1.14.0",
"electron-find": "1.0.6",
"electron-spellchecker": "2.2.0",
"electron-window-state": "5.0.3",
"express": "4.17.1",
"express-session": "1.16.2",
"express-session": "1.17.0",
"file-type": "12.3.0",
"fs-extra": "8.1.0",
"helmet": "3.21.1",
"html": "1.0.0",
"html2plaintext": "2.1.2",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.2",
"http-proxy-agent": "2.1.0",
"https-proxy-agent": "3.0.0",
"image-type": "4.1.0",
"imagemin": "7.0.0",
"imagemin-giflossy": "5.1.10",
@@ -70,7 +69,7 @@
"simple-node-logger": "18.12.23",
"sqlite": "3.0.3",
"sqlite3": "4.1.0",
"string-similarity": "^3.0.0",
"string-similarity": "3.0.0",
"tar-stream": "2.1.0",
"turndown": "5.0.3",
"turndown-plugin-gfm": "1.0.2",
@@ -85,7 +84,7 @@
"electron-installer-debian": "2.0.1",
"electron-packager": "14.0.6",
"electron-rebuild": "1.8.6",
"jsdoc": "^3.6.3",
"jsdoc": "3.6.3",
"lorem-ipsum": "2.0.3",
"xo": "0.25.3"
},

View File

@@ -88,7 +88,10 @@ app.use((req, res, next) => {
// error handler
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
}
else {

View File

@@ -29,6 +29,7 @@ import macInit from './services/mac_init.js';
import cssLoader from './services/css_loader.js';
import dateNoteService from './services/date_notes.js';
import sidebarService from './services/sidebar.js';
import importService from './services/import.js';
window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile;
@@ -177,3 +178,7 @@ entrypoints.registerEntrypoints();
noteTooltipService.setupGlobalTooltip();
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 treeUtils from "../services/tree_utils.js";
import server from "../services/server.js";
import infoService from "../services/info.js";
import ws from "../services/ws.js";
import importService from "../services/import.js";
const $dialog = $("#import-dialog");
const $form = $("#import-form");
const $noteTitle = $dialog.find(".import-note-title");
const $fileUploadInput = $("#import-file-upload-input");
const $importProgressCountWrapper = $("#import-progress-count-wrapper");
const $importProgressCount = $("#import-progress-count");
const $importButton = $("#import-button");
const $safeImportCheckbox = $("#safe-import-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 $explodeArchivesCheckbox = $("#explode-archives-checkbox");
let importId;
let importIntoNoteId = null;
let parentNoteId = null;
export async function showDialog(node) {
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
$safeImportCheckbox.prop("checked", true);
@@ -38,9 +28,9 @@ export async function showDialog(node) {
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();
}
@@ -49,18 +39,14 @@ $form.submit(() => {
// disabling so that import is not triggered again.
$importButton.attr("disabled", "disabled");
importIntoNote(importIntoNoteId);
importIntoNote(parentNoteId);
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
// 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 = {
safeImport: boolToString($safeImportCheckbox),
shrinkImages: boolToString($shrinkImagesCheckbox),
@@ -69,73 +55,15 @@ async function importIntoNote(importNoteId) {
explodeArchives: boolToString($explodeArchivesCheckbox)
};
await uploadFiles(importNoteId, files, options);
$dialog.modal('hide');
}
export async function uploadFiles(importNoteId, 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);
}
await importService.uploadFiles(parentNoteId, files, options);
}
function boolToString($el) {
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(() => {
if ($fileUploadInput.val()) {
$importButton.removeAttr("disabled");

View File

@@ -62,14 +62,4 @@ $list.on('change', () => {
else {
$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/code_notes.js'),
import('./options/change_password.js'),
import('./options/note_revisions.js'),
import('./options/protected_session.js'),
import('./options/other.js'),
import('./options/sidebar.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);
}
async function executeBundle(bundle, originEntity, tabContext) {
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext);
async function executeBundle(bundle, originEntity, tabContext, $container) {
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext, $container);
try {
return await (function () {

View File

@@ -30,9 +30,9 @@ const dragAndDropSetup = {
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
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,
shrinkImages: true,
textImportedAsText: true,

View File

@@ -172,6 +172,19 @@ function registerEntrypoints() {
utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor);
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 {

View File

@@ -16,9 +16,12 @@ import StandardWidget from '../widgets/standard_widget.js';
* @constructor
* @hideconstructor
*/
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) {
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
const $pluginButtons = $("#plugin-buttons");
/** @property {jQuery} container of all the rendered script content */
this.$container = $container;
/** @property {object} note where script started executing */
this.startNote = startNote;
/** @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 utils from "./utils.js";
function showMessage(message) {
function showMessage(message, delay = 3000) {
console.debug(utils.now(), "message: ", message);
$.notify({
icon: 'jam jam-check',
message: message
}, getNotifySettings('success', 3000));
}, getNotifySettings('success', delay));
}
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) {
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
noteTitle = await treeUtils.getNoteTitle(noteId);
}
const noteLink = $("<a>", {
const $noteLink = $("<a>", {
href: 'javascript:',
text: noteTitle
}).attr('data-action', 'note')
.attr('data-note-path', notePath);
return noteLink;
if (!tooltip) {
$noteLink.addClass("no-tooltip-preview");
}
return $noteLink;
}
async function createNoteLinkWithPath(notePath, noteTitle = null) {
@@ -113,7 +117,7 @@ function addTextToEditor(text) {
}
}
function tabContextMenu(e) {
function newTabContextMenu(e) {
const $link = $(e.target);
const notePath = getNotePathFromLink($link);
@@ -138,9 +142,9 @@ function tabContextMenu(e) {
});
}
$(document).on('contextmenu', '.note-detail-text a', tabContextMenu);
$(document).on('contextmenu', "a[data-action='note']", tabContextMenu);
$(document).on('contextmenu', ".note-detail-render a", tabContextMenu);
$(document).on('contextmenu', '.note-detail-text a', newTabContextMenu);
$(document).on('contextmenu', "a[data-action='note']", newTabContextMenu);
$(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
// 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-text.ck-read-only a', goToLink);
$(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 importDialog = await import("../dialogs/import.js");
const importService = await import("./import.js");
importDialog.uploadFiles(activeNote.noteId, files, {
importService.uploadFiles(activeNote.noteId, files, {
safeImport: true,
shrinkImages: true,
textImportedAsText: true,
@@ -385,6 +385,8 @@ tabRow.addListener('tabRemove', async ({ detail }) => {
});
$(tabRow.el).on('contextmenu', '.note-tab', e => {
e.preventDefault();
const tab = $(e.target).closest(".note-tab");
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 server from "./server.js";
import renderService from "./render.js";
class NoteDetailRender {
/**
@@ -16,29 +15,10 @@ class NoteDetailRender {
}
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.$noteDetailRenderHelp.hide();
this.$noteDetailRenderContent.empty();
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);
}
}
await renderService.render(this.ctx.note, this.$noteDetailRenderContent, this.ctx);
}
getContent() {}

View File

@@ -11,6 +11,7 @@ const NOTE_TYPES = [
{ type: "text", mime: "text/html", title: "Text", selectable: true },
{ type: "relation-map", mime: "application/json", title: "Relation Map", 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 }
];

View File

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

View File

@@ -46,8 +46,7 @@ async function setupProtectedSession(password) {
await treeService.reload();
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for children overview)
// children overview is the reason why we need to reload all tabs
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for book)
await noteDetailService.reloadAllTabs();
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 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 startNote = await treeCache.getNote(startNoteId);
@@ -11,7 +11,7 @@ async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabCo
return {
modules: modules,
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 => {
return moduleName => {
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",
'render': "./note_detail_render.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;
@@ -64,7 +65,6 @@ class TabContext {
this.$notePathList = this.$tabContent.find(".note-path-list");
this.$notePathCount = this.$tabContent.find(".note-path-count");
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.$savedIndicator = this.$tabContent.find(".saved-indicator");
this.noteChangeDisabled = false;
@@ -115,13 +115,13 @@ class TabContext {
await this.initComponent();
}
async initComponent() {
const type = this.getComponentType();
async initComponent(disableAutoBook = false) {
this.type = this.getComponentType(disableAutoBook);
if (!(type in this.components)) {
const clazz = await import(componentClasses[type]);
if (!(this.type in this.components)) {
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.closeAutocomplete(); // esp. on windows autocomplete is not getting closed automatically
this.cleanup(); // esp. on windows autocomplete is not getting closed automatically
setTimeout(async () => {
// 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()) {
this.noteType.update();
this.showChildrenOverview();
}
if (this.sidebar) {
@@ -210,11 +208,11 @@ class TabContext {
this.setTitleBar();
}
async renderComponent() {
await this.initComponent();
async renderComponent(disableAutoBook = false) {
await this.initComponent(disableAutoBook);
for (const componentType in this.components) {
if (componentType !== this.getComponentType()) {
if (componentType !== this.type) {
this.components[componentType].cleanup();
}
}
@@ -283,30 +281,31 @@ class TabContext {
}
getComponent() {
const type = this.getComponentType();
return this.components[type];
return this.components[this.type];
}
getComponentType() {
let type;
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';
getComponentType(disableAutoBook) {
if (!this.note) {
return "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;
}
@@ -365,33 +364,6 @@ class TabContext {
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) {
const title = await treeUtils.getNotePathTitle(notePath);
@@ -440,15 +412,17 @@ class TabContext {
async remove() {
// sometimes there are orphan autocompletes after closing the tab
this.closeAutocomplete();
this.cleanup();
await this.saveNoteIfChanged();
this.$tabContent.remove();
}
closeAutocomplete() {
if (utils.isDesktop()) {
cleanup() {
if (this.$tabContent && utils.isDesktop()) {
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) {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
@@ -48,23 +58,8 @@ async function getIcon(note) {
return "jam jam-file";
}
}
else if (note.type === 'file') {
return "jam jam-attachment"
}
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"
else {
return NOTE_TYPE_ICONS[note.type];
}
}
@@ -161,6 +156,10 @@ async function getExtraClasses(note) {
extraClasses.push(utils.getMimeTypeClass(note.mime));
}
if (note.archived) {
extraClasses.push("archived");
}
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 {
reloadApp,
parseDate,
@@ -231,5 +235,6 @@ export default {
getCookie,
getNoteTypeClass,
getMimeTypeClass,
closeActiveDialog
closeActiveDialog,
isHtmlEmpty
};

View File

@@ -1,5 +1,6 @@
import utils from './utils.js';
import infoService from "./info.js";
import treeService from "./tree.js";
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');
$showFullButton.click(async () => {
const attributesDialog = await import("../dialogs/note_revisions.js");
attributesDialog.showDialog();
attributesDialog.showCurrentNoteRevisions(this.ctx.note.noteId);
});
return [$showFullButton];

View File

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

View File

@@ -75,9 +75,4 @@
.note-detail-relation-map .ui-contextmenu {
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%;
display: flex;
flex-direction: column;
min-height: 200px;
min-height: 500px;
overflow-wrap: break-word; /* otherwise CKEditor fails miserably on super long lines */
font-family: var(--detail-font-family);
font-size: var(--detail-font-size);
@@ -136,7 +136,7 @@ ul.fancytree-container {
border: 0 !important;
box-shadow: none !important;
/* 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 {
@@ -213,6 +213,10 @@ span.fancytree-node:hover span.fancytree-title {
border-radius: 5px;
}
span.fancytree-node.archived {
opacity: 0.6;
}
.ui-autocomplete {
max-height: 300px;
overflow-y: auto;
@@ -353,11 +357,11 @@ div.ui-tooltip {
}
.note-detail-code-editor {
min-height: 200px;
min-height: 500px;
}
.note-detail-render {
min-height: 200px;
min-height: 500px;
}
.CodeMirror {
@@ -367,7 +371,7 @@ div.ui-tooltip {
}
.CodeMirror-scroll {
min-height: 200px;
min-height: 500px;
}
.CodeMirror-gutters {
@@ -390,37 +394,6 @@ div.ui-tooltip {
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 {
height: 150px;
width: 100%;
@@ -817,4 +790,71 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
.modal-header {
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-text-color: black;
--main-border-color: #ccc;
--accented-background-color: #eee;
--accented-background-color: #f5f5f5;
--more-accented-background-color: #ccc;
--header-background-color: #f8f8f8;
--button-background-color: #eee;
@@ -183,6 +183,8 @@ body {
/* todo lists */
--ck-color-todo-list-checkmark-border: var(--main-border-color);
--ck-color-engine-placeholder-text: var(--main-text-color);
}
body {

View File

@@ -13,7 +13,7 @@ const ImportContext = require('../../services/import_context');
async function importToBranch(req) {
const {parentNoteId} = req.params;
const {importId} = req.body;
const {importId, last} = req.body;
const options = {
safeImport: req.body.safeImport !== 'false',
@@ -65,6 +65,11 @@ async function importToBranch(req) {
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
// instead we force it to reload (can be async)
noteCacheService.load();

View File

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

View File

@@ -75,6 +75,7 @@ async function forceNoteSync(req) {
const noteId = req.params.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])) {
await syncTableService.addBranchSync(branchId);

View File

@@ -3,6 +3,7 @@
const sql = require('../../services/sql');
const optionService = require('../../services/options');
const protectedSessionService = require('../../services/protected_session');
const noteCacheService = require('../../services/note_cache');
async function getNotes(noteIds) {
const notes = await sql.getManyRows(`
@@ -31,7 +32,11 @@ async function getNotes(noteIds) {
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;
}

View File

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

View File

@@ -17,12 +17,12 @@ const BUILTIN_ATTRIBUTES = [
{ type: 'label', name: 'disableInclusion' },
{ type: 'label', name: 'appCss' },
{ type: 'label', name: 'appTheme' },
{ type: 'label', name: 'hideChildrenOverview' },
{ type: 'label', name: 'hidePromotedAttributes' },
{ type: 'label', name: 'readOnly' },
{ type: 'label', name: 'run', isDangerous: true },
{ type: 'label', name: 'customRequestHandler', isDangerous: true },
{ type: 'label', name: 'customResourceProvider', isDangerous: true },
{ type: 'label', name: 'bookZoomLevel', isDangerous: false },
// relation names
{ 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
WHERE
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}`);
await findIssues(`

View File

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

View File

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

View File

@@ -14,6 +14,7 @@ const commonmark = require('commonmark');
const ImportContext = require('../import_context');
const protectedSessionService = require('../protected_session');
const mimeService = require("./mime");
const treeService = require("../tree");
/**
* @param {ImportContext} importContext
@@ -115,11 +116,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
function getNoteId(noteMeta, filePath) {
const filePathNoExt = getTextFileWithoutExtension(filePath);
console.log(`Searching for noteId of filePath ${filePath} with meta: ${!!noteMeta}`);
if (filePathNoExt in createdPaths) {
console.log("Found existing path", filePathNoExt, createdPaths[filePathNoExt]);
return createdPaths[filePathNoExt];
}
@@ -131,7 +128,7 @@ async function importTar(importContext, fileBuffer, importRootNote) {
}
function detectFileTypeAndMime(importContext, filePath) {
const mime = mimeService.getMime(filePath);
const mime = mimeService.getMime(filePath) || "application/octet-stream";
const type = mimeService.getType(importContext, mime);
return { mime, type };
@@ -426,6 +423,12 @@ async function importTar(importContext, fileBuffer, importRootNote) {
for (const noteId in createdNoteIds) { // now the noteIds are unique
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();
}

View File

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

View File

@@ -86,9 +86,12 @@ async function findNotes(query) {
return [];
}
// trim is necessary because even with .split() trailing spaces are tokens which causes havoc
// filtering '/' because it's used as separator
const allTokens = query.trim().toLowerCase().split(" ").filter(token => token !== '/');
const allTokens = query
.trim() // necessary because even with .split() trailing spaces are tokens which causes havoc
.toLowerCase()
.split(/[ -]/)
.filter(token => token !== '/'); // '/' is used as separator
const tokens = allTokens.slice();
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('initialized', initialized ? 'true' : 'false', false);
await optionService.createOption('spellCheckEnabled', 'true', false);
await optionService.createOption('spellCheckLanguageCode', 'en-US', false);
}
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 () => {
const notes = await sql.getRows(`SELECT branchId, noteId, title, isProtected
FROM notes JOIN branches USING(noteId)
WHERE branches.isDeleted = 0 AND parentNoteId = ?`, [parentNoteId]);
const notes = await sql.getRows(
`SELECT branches.branchId, notes.noteId, title, isProtected,
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);
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;

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">
<input class="form-check-input" type="radio" name="export-subtree-format" id="export-subtree-format-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 class="form-check">

View File

@@ -9,10 +9,6 @@
</div>
<form id="import-form">
<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">
<label for="import-file-upload-input"><strong>Choose import file</strong></label>

View File

@@ -22,15 +22,12 @@
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-change-password">Change password</a>
</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">
<a class="nav-link" data-toggle="tab" href="#options-sync-setup">Sync</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-other">Other</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#options-advanced">Advanced</a>
</li>
@@ -41,8 +38,7 @@
<% include options/sidebar.ejs %>
<% include options/code_notes.ejs %>
<% include options/change_password.ejs %>
<% include options/protected_session.ejs %>
<% include options/note_revisions.ejs %>
<% include options/other.ejs %>
<% include options/sync.ejs %>
<% include options/advanced.ejs %>
</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 %>
<div class="children-overview hide-toggle"></div>
<% include details/book.ejs %>
</div>
</div>