mirror of
https://github.com/zadam/trilium.git
synced 2025-11-02 11:26:15 +01:00
Compare commits
72 Commits
v0.35.1
...
v0.36.1-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41d47c5d33 | ||
|
|
132360b46b | ||
|
|
f0496cb42c | ||
|
|
1522297700 | ||
|
|
2a5ab3a5e1 | ||
|
|
358fd13c8d | ||
|
|
2305ad7405 | ||
|
|
78f5b7b288 | ||
|
|
1903c59163 | ||
|
|
b16c2d19b6 | ||
|
|
00bb1236ce | ||
|
|
82bbf4173b | ||
|
|
9f4ca279aa | ||
|
|
b890859025 | ||
|
|
56e4f4f5ac | ||
|
|
157bd3816d | ||
|
|
21588829c7 | ||
|
|
9689029c4b | ||
|
|
992d174b23 | ||
|
|
8886e95847 | ||
|
|
6d5762fac8 | ||
|
|
e9ab044e46 | ||
|
|
fda219d070 | ||
|
|
2be1aca2f3 | ||
|
|
1b318d6a30 | ||
|
|
22c4859d42 | ||
|
|
80a6361cf1 | ||
|
|
8439effeeb | ||
|
|
fafab95a07 | ||
|
|
24c8e8fc2b | ||
|
|
1923bf7dda | ||
|
|
2ee94a3a69 | ||
|
|
2fb3a3eff9 | ||
|
|
bcbbf4dc3e | ||
|
|
7dc793920f | ||
|
|
0b43eceb2d | ||
|
|
85f736139b | ||
|
|
98a6670cb4 | ||
|
|
a15be82f00 | ||
|
|
6c3809e1db | ||
|
|
33a2cd21a3 | ||
|
|
3eebce22e7 | ||
|
|
adae0625b9 | ||
|
|
5063cfb979 | ||
|
|
0835930a8a | ||
|
|
c9432990b7 | ||
|
|
9ad521822d | ||
|
|
824fb08511 | ||
|
|
cc4c15daf0 | ||
|
|
7718778013 | ||
|
|
a25260353d | ||
|
|
c1e8a4b384 | ||
|
|
3f2229d9e1 | ||
|
|
8561227622 | ||
|
|
8859e2ac40 | ||
|
|
7423b2f4fd | ||
|
|
d23e9f1bc4 | ||
|
|
516277a478 | ||
|
|
cbc7710d81 | ||
|
|
ea71e96f72 | ||
|
|
59d1cb1833 | ||
|
|
7c54ba63ce | ||
|
|
5892b5b851 | ||
|
|
02eb737b9d | ||
|
|
144e75da9e | ||
|
|
8d14a0d687 | ||
|
|
dec2c218f7 | ||
|
|
dd147a7209 | ||
|
|
c3fabcb666 | ||
|
|
35e825b376 | ||
|
|
334a38c493 | ||
|
|
8ec01c73cd |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ yarn-error.log
|
|||||||
config.ini
|
config.ini
|
||||||
cert.key
|
cert.key
|
||||||
cert.crt
|
cert.crt
|
||||||
|
server-package.json
|
||||||
15
.gitpod.dockerfile
Normal file
15
.gitpod.dockerfile
Normal 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/*
|
||||||
|
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
|
image:
|
||||||
|
file: .gitpod.dockerfile
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- before: nvm install 10 && nvm use 10
|
- before: nvm install 10 && nvm use 10
|
||||||
init: npm install
|
init: npm install
|
||||||
command: npm run start
|
command: npm run start-server
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- port: 8080
|
- port: 8080
|
||||||
onOpen: open-preview
|
onOpen: open-preview
|
||||||
@@ -57,7 +57,6 @@
|
|||||||
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1">
|
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>apiTokenId</ColNames>
|
<ColNames>apiTokenId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="25" parent="6">
|
<key id="25" parent="6">
|
||||||
@@ -126,25 +125,20 @@
|
|||||||
<index id="37" parent="7" name="sqlite_autoindex_attributes_1">
|
<index id="37" parent="7" name="sqlite_autoindex_attributes_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>attributeId</ColNames>
|
<ColNames>attributeId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<index id="38" parent="7" name="IDX_attributes_noteId_index">
|
<index id="38" parent="7" name="IDX_attributes_noteId_index">
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="39" parent="7" name="IDX_attributes_name_value">
|
<index id="39" parent="7" name="IDX_attributes_name_value">
|
||||||
<ColNames>name
|
<ColNames>name
|
||||||
value</ColNames>
|
value</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="40" parent="7" name="IDX_attributes_name_index">
|
<index id="40" parent="7" name="IDX_attributes_name_index">
|
||||||
<ColNames>name</ColNames>
|
<ColNames>name</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="41" parent="7" name="IDX_attributes_value_index">
|
<index id="41" parent="7" name="IDX_attributes_value_index">
|
||||||
<ColNames>value</ColNames>
|
<ColNames>value</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<key id="42" parent="7">
|
<key id="42" parent="7">
|
||||||
<ColNames>attributeId</ColNames>
|
<ColNames>attributeId</ColNames>
|
||||||
@@ -204,21 +198,17 @@ value</ColNames>
|
|||||||
<index id="53" parent="8" name="sqlite_autoindex_branches_1">
|
<index id="53" parent="8" name="sqlite_autoindex_branches_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>branchId</ColNames>
|
<ColNames>branchId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<index id="54" parent="8" name="IDX_branches_noteId_parentNoteId">
|
<index id="54" parent="8" name="IDX_branches_noteId_parentNoteId">
|
||||||
<ColNames>noteId
|
<ColNames>noteId
|
||||||
parentNoteId</ColNames>
|
parentNoteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="55" parent="8" name="IDX_branches_noteId">
|
<index id="55" parent="8" name="IDX_branches_noteId">
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="56" parent="8" name="IDX_branches_parentNoteId">
|
<index id="56" parent="8" name="IDX_branches_parentNoteId">
|
||||||
<ColNames>parentNoteId</ColNames>
|
<ColNames>parentNoteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<key id="57" parent="8">
|
<key id="57" parent="8">
|
||||||
<ColNames>branchId</ColNames>
|
<ColNames>branchId</ColNames>
|
||||||
@@ -246,7 +236,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="62" parent="9" name="sqlite_autoindex_event_log_1">
|
<index id="62" parent="9" name="sqlite_autoindex_event_log_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>eventId</ColNames>
|
<ColNames>eventId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="63" parent="9">
|
<key id="63" parent="9">
|
||||||
@@ -278,7 +267,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="68" parent="10" name="sqlite_autoindex_note_contents_1">
|
<index id="68" parent="10" name="sqlite_autoindex_note_contents_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="69" parent="10">
|
<key id="69" parent="10">
|
||||||
@@ -351,20 +339,16 @@ parentNoteId</ColNames>
|
|||||||
<index id="82" parent="11" name="sqlite_autoindex_note_revisions_1">
|
<index id="82" parent="11" name="sqlite_autoindex_note_revisions_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>noteRevisionId</ColNames>
|
<ColNames>noteRevisionId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<index id="83" parent="11" name="IDX_note_revisions_noteId">
|
<index id="83" parent="11" name="IDX_note_revisions_noteId">
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="84" parent="11" name="IDX_note_revisions_dateModifiedFrom">
|
<index id="84" parent="11" name="IDX_note_revisions_dateModifiedFrom">
|
||||||
<ColNames>utcDateModifiedFrom</ColNames>
|
<ColNames>utcDateModifiedFrom</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<index id="85" parent="11" name="IDX_note_revisions_dateModifiedTo">
|
<index id="85" parent="11" name="IDX_note_revisions_dateModifiedTo">
|
||||||
<ColNames>utcDateModifiedTo</ColNames>
|
<ColNames>utcDateModifiedTo</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<key id="86" parent="11">
|
<key id="86" parent="11">
|
||||||
<ColNames>noteRevisionId</ColNames>
|
<ColNames>noteRevisionId</ColNames>
|
||||||
@@ -435,7 +419,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="98" parent="12" name="sqlite_autoindex_notes_1">
|
<index id="98" parent="12" name="sqlite_autoindex_notes_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="99" parent="12">
|
<key id="99" parent="12">
|
||||||
@@ -477,7 +460,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="106" parent="13" name="sqlite_autoindex_options_1">
|
<index id="106" parent="13" name="sqlite_autoindex_options_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>name</ColNames>
|
<ColNames>name</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="107" parent="13">
|
<key id="107" parent="13">
|
||||||
@@ -513,7 +495,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="113" parent="14" name="sqlite_autoindex_recent_notes_1">
|
<index id="113" parent="14" name="sqlite_autoindex_recent_notes_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>noteId</ColNames>
|
<ColNames>noteId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="114" parent="14">
|
<key id="114" parent="14">
|
||||||
@@ -534,7 +515,6 @@ parentNoteId</ColNames>
|
|||||||
<index id="117" parent="15" name="sqlite_autoindex_source_ids_1">
|
<index id="117" parent="15" name="sqlite_autoindex_source_ids_1">
|
||||||
<NameSurrogate>1</NameSurrogate>
|
<NameSurrogate>1</NameSurrogate>
|
||||||
<ColNames>sourceId</ColNames>
|
<ColNames>sourceId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<key id="118" parent="15">
|
<key id="118" parent="15">
|
||||||
@@ -597,12 +577,10 @@ parentNoteId</ColNames>
|
|||||||
<index id="131" parent="18" name="IDX_sync_entityName_entityId">
|
<index id="131" parent="18" name="IDX_sync_entityName_entityId">
|
||||||
<ColNames>entityName
|
<ColNames>entityName
|
||||||
entityId</ColNames>
|
entityId</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
<Unique>1</Unique>
|
<Unique>1</Unique>
|
||||||
</index>
|
</index>
|
||||||
<index id="132" parent="18" name="IDX_sync_utcSyncDate">
|
<index id="132" parent="18" name="IDX_sync_utcSyncDate">
|
||||||
<ColNames>utcSyncDate</ColNames>
|
<ColNames>utcSyncDate</ColNames>
|
||||||
<ColumnCollations></ColumnCollations>
|
|
||||||
</index>
|
</index>
|
||||||
<key id="133" parent="18">
|
<key id="133" parent="18">
|
||||||
<ColNames>id</ColNames>
|
<ColNames>id</ColNames>
|
||||||
|
|||||||
6
.idea/jsLibraryMappings.xml
generated
Normal file
6
.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptLibraryMappings">
|
||||||
|
<file url="PROJECT" libraries="{@types/jquery}" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
FROM node:12.10.0-alpine
|
FROM node:12.12.0-alpine
|
||||||
|
|
||||||
# Create app directory
|
# Create app directory
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
# Copy both package.json and package-lock.json
|
COPY server-package.json package.json
|
||||||
# where available (npm@5+)
|
|
||||||
COPY package.json package-lock.json ./
|
|
||||||
|
|
||||||
# Install app dependencies
|
# Install app dependencies
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
|
|||||||
@@ -46,5 +46,5 @@ Use a browser based dev environment
|
|||||||
Or clone locally and run
|
Or clone locally and run
|
||||||
```
|
```
|
||||||
npm install
|
npm install
|
||||||
npm run start
|
npm run start-server
|
||||||
```
|
```
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
VERSION=`jq -r ".version" package.json`
|
VERSION=`jq -r ".version" package.json`
|
||||||
SERIES=${VERSION:0:4}-latest
|
SERIES=${VERSION:0:4}-latest
|
||||||
|
|
||||||
|
cat package.json | grep -v electron > server-package.json
|
||||||
|
|
||||||
sudo docker build -t zadam/trilium:$VERSION -t zadam/trilium:$SERIES .
|
sudo docker build -t zadam/trilium:$VERSION -t zadam/trilium:$SERIES .
|
||||||
|
|
||||||
if [[ $VERSION != *"beta"* ]]; then
|
if [[ $VERSION != *"beta"* ]]; then
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
BUILD_DIR=./dist/trilium-linux-x64
|
SRC_DIR=./dist/trilium-linux-x64-src
|
||||||
rm -rf $BUILD_DIR
|
|
||||||
|
if [ "$1" != "DONTCOPY" ]
|
||||||
|
then
|
||||||
|
./bin/copy-trilium.sh $SRC_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Copying required linux-x64 binaries"
|
echo "Copying required linux-x64 binaries"
|
||||||
|
|
||||||
rm -r node_modules/sqlite3/lib/binding/*
|
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
|
||||||
rm -r node_modules/pngquant-bin/vendor/*
|
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
|
||||||
|
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
|
||||||
|
|
||||||
cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
cp -r bin/deps/linux-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
|
||||||
cp bin/deps/linux-x64/image/pngquant node_modules/pngquant-bin/vendor/
|
cp bin/deps/linux-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
|
||||||
|
cp bin/deps/linux-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
|
||||||
|
|
||||||
# rebuild binaries for image operations (pngquant ...)
|
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
|
||||||
npm rebuild
|
|
||||||
|
|
||||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
|
BUILD_DIR=./dist/trilium-linux-x64
|
||||||
|
rm -rf $BUILD_DIR
|
||||||
|
|
||||||
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
|
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
|
||||||
|
|
||||||
@@ -29,3 +35,7 @@ VERSION=`jq -r ".version" package.json`
|
|||||||
cd dist
|
cd dist
|
||||||
|
|
||||||
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
|
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
bin/build-debian.sh
|
||||||
@@ -1,27 +1,36 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
SRC_DIR=./dist/trilium-mac-x64-src
|
||||||
|
|
||||||
|
if [ "$1" != "DONTCOPY" ]
|
||||||
|
then
|
||||||
|
./bin/copy-trilium.sh $SRC_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying required mac binaries"
|
||||||
|
|
||||||
|
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
|
||||||
|
rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
|
||||||
|
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
|
||||||
|
rm -r $SRC_DIR/node_modules/giflossy/vendor/*
|
||||||
|
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
|
||||||
|
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
|
||||||
|
|
||||||
|
cp -r bin/deps/mac-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
|
||||||
|
cp bin/deps/mac-x64/image/cjpeg $SRC_DIR/node_modules/mozjpeg/vendor/
|
||||||
|
cp bin/deps/mac-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/
|
||||||
|
cp bin/deps/mac-x64/image/gifsicle $SRC_DIR/node_modules/giflossy/vendor/
|
||||||
|
cp bin/deps/mac-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
|
||||||
|
cp bin/deps/mac-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
|
||||||
|
|
||||||
|
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns
|
||||||
|
|
||||||
BUILD_DIR=./dist/trilium-mac-x64
|
BUILD_DIR=./dist/trilium-mac-x64
|
||||||
rm -rf $BUILD_DIR
|
rm -rf $BUILD_DIR
|
||||||
|
|
||||||
echo "Copying required mac binaries"
|
|
||||||
|
|
||||||
rm -r node_modules/sqlite3/lib/binding/*
|
|
||||||
rm -r node_modules/mozjpeg/vendor/*
|
|
||||||
rm -r node_modules/pngquant-bin/vendor/*
|
|
||||||
rm -r node_modules/giflossy/vendor/*
|
|
||||||
|
|
||||||
cp -r bin/deps/mac-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
|
||||||
cp bin/deps/mac-x64/image/cjpeg node_modules/mozjpeg/vendor/
|
|
||||||
cp bin/deps/mac-x64/image/pngquant node_modules/pngquant-bin/vendor/
|
|
||||||
cp bin/deps/mac-x64/image/gifsicle node_modules/giflossy/vendor/
|
|
||||||
|
|
||||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns
|
|
||||||
|
|
||||||
# Mac build has by default useless directory level
|
# Mac build has by default useless directory level
|
||||||
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
|
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
|
||||||
|
|
||||||
./bin/reset-local.sh
|
|
||||||
|
|
||||||
echo "Zipping mac x64 electron distribution..."
|
echo "Zipping mac x64 electron distribution..."
|
||||||
|
|
||||||
VERSION=`jq -r ".version" package.json`
|
VERSION=`jq -r ".version" package.json`
|
||||||
|
|||||||
@@ -1,40 +1,32 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
PKG_DIR=dist/trilium-linux-x64-server
|
PKG_DIR=dist/trilium-linux-x64-server
|
||||||
NODE_VERSION=12.10.0
|
NODE_VERSION=12.12.0
|
||||||
|
|
||||||
rm -r $PKG_DIR
|
if [ "$1" != "DONTCOPY" ]
|
||||||
mkdir $PKG_DIR
|
then
|
||||||
cd $PKG_DIR
|
./bin/copy-trilium.sh $PKG_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd dist
|
||||||
wget https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz
|
wget https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz
|
||||||
tar xvfJ node-v${NODE_VERSION}-linux-x64.tar.xz
|
tar xvfJ node-v${NODE_VERSION}-linux-x64.tar.xz
|
||||||
rm node-v${NODE_VERSION}-linux-x64.tar.xz
|
rm node-v${NODE_VERSION}-linux-x64.tar.xz
|
||||||
|
|
||||||
mv node-v${NODE_VERSION}-linux-x64 node
|
|
||||||
|
|
||||||
cp -r ../../node_modules/ ./
|
|
||||||
cp -r ../../images/ ./
|
|
||||||
cp -r ../../libraries/ ./
|
|
||||||
cp -r ../../src/ ./
|
|
||||||
cp -r ../../db/ ./
|
|
||||||
cp -r ../../package.json ./
|
|
||||||
cp -r ../../package-lock.json ./
|
|
||||||
cp -r ../../README.md ./
|
|
||||||
cp -r ../../LICENSE ./
|
|
||||||
cp -r ../../config-sample.ini ./
|
|
||||||
|
|
||||||
rm -r ./node_modules/electron*
|
|
||||||
|
|
||||||
rm -r ./node_modules/sqlite3/lib/binding/*
|
|
||||||
|
|
||||||
cp -r ../../bin/deps/linux-x64/sqlite/node* ./node_modules/sqlite3/lib/binding/
|
|
||||||
|
|
||||||
printf "#!/bin/sh\n./node/bin/node src/www" > trilium.sh
|
|
||||||
chmod 755 trilium.sh
|
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
VERSION=`jq -r ".version" ../package.json`
|
mv dist/node-v${NODE_VERSION}-linux-x64 $PKG_DIR/node
|
||||||
|
|
||||||
|
rm -r $PKG_DIR/node_modules/electron*
|
||||||
|
|
||||||
|
rm -r $PKG_DIR/node_modules/sqlite3/lib/binding/*
|
||||||
|
|
||||||
|
cp -r ./bin/deps/linux-x64/sqlite/node* $PKG_DIR/node_modules/sqlite3/lib/binding/
|
||||||
|
|
||||||
|
printf "#!/bin/sh\n./node/bin/node src/www" > $PKG_DIR/trilium.sh
|
||||||
|
chmod 755 $PKG_DIR/trilium.sh
|
||||||
|
|
||||||
|
VERSION=`jq -r ".version" package.json`
|
||||||
|
|
||||||
|
cd dist
|
||||||
|
|
||||||
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server
|
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
BUILD_DIR=./dist/trilium-windows-x64
|
SRC_DIR=./dist/trilium-windows-x64-src
|
||||||
rm -rf $BUILD_DIR
|
|
||||||
|
if [ "$1" != "DONTCOPY" ]
|
||||||
|
then
|
||||||
|
./bin/copy-trilium.sh $SRC_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Copying required windows binaries"
|
echo "Copying required windows binaries"
|
||||||
|
|
||||||
rm -r node_modules/sqlite3/lib/binding/*
|
rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/*
|
||||||
rm -r node_modules/mozjpeg/vendor/*
|
rm -r $SRC_DIR/node_modules/mozjpeg/vendor/*
|
||||||
rm -r node_modules/pngquant-bin/vendor/*
|
rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/*
|
||||||
rm -r node_modules/giflossy/vendor/*
|
rm -r $SRC_DIR/node_modules/giflossy/vendor/*
|
||||||
|
rm -r $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/*
|
||||||
|
rm -r $SRC_DIR/node_modules/keyboard-layout/build/Release/*
|
||||||
|
|
||||||
cp -r bin/deps/win-x64/sqlite/* node_modules/sqlite3/lib/binding/
|
cp -r bin/deps/win-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/
|
||||||
cp bin/deps/win-x64/image/cjpeg.exe node_modules/mozjpeg/vendor/
|
cp bin/deps/win-x64/image/cjpeg.exe $SRC_DIR/node_modules/mozjpeg/vendor/
|
||||||
cp bin/deps/win-x64/image/pngquant.exe node_modules/pngquant-bin/vendor/
|
cp bin/deps/win-x64/image/pngquant.exe $SRC_DIR/node_modules/pngquant-bin/vendor/
|
||||||
cp bin/deps/win-x64/image/gifsicle.exe node_modules/giflossy/vendor/
|
cp bin/deps/win-x64/image/gifsicle.exe $SRC_DIR/node_modules/giflossy/vendor/
|
||||||
|
cp bin/deps/win-x64/spellchecker/* $SRC_DIR/node_modules/@felixrieseberg/spellchecker/build/Release/
|
||||||
|
cp bin/deps/win-x64/keyboard-layout-manager.node $SRC_DIR/node_modules/keyboard-layout/build/Release/
|
||||||
|
|
||||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico
|
./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico
|
||||||
|
|
||||||
|
BUILD_DIR=./dist/trilium-windows-x64
|
||||||
|
rm -rf $BUILD_DIR
|
||||||
|
|
||||||
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
|
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
|
||||||
|
|
||||||
# removing software WebGL binaries because they are pretty huge and not necessary
|
# removing software WebGL binaries because they are pretty huge and not necessary
|
||||||
rm -r $BUILD_DIR/swiftshader
|
rm -r $BUILD_DIR/swiftshader
|
||||||
|
|
||||||
./bin/reset-local.sh
|
|
||||||
|
|
||||||
echo "Zipping windows x64 electron distribution..."
|
echo "Zipping windows x64 electron distribution..."
|
||||||
VERSION=`jq -r ".version" package.json`
|
VERSION=`jq -r ".version" package.json`
|
||||||
|
|
||||||
|
|||||||
24
bin/build.sh
24
bin/build.sh
@@ -1,21 +1,23 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
rm -r node_modules
|
|
||||||
|
|
||||||
npm install
|
|
||||||
|
|
||||||
echo "Deleting existing builds"
|
echo "Deleting existing builds"
|
||||||
|
|
||||||
rm -r dist/*
|
rm -r dist/*
|
||||||
|
|
||||||
bin/build-win-x64.sh
|
SRC_DIR=dist/trilium-src
|
||||||
|
|
||||||
bin/build-mac-x64.sh
|
bin/copy-trilium.sh $SRC_DIR
|
||||||
|
|
||||||
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development
|
# we'll just copy the same SRC dir to all the builds so we don't have to do npm install in each separately
|
||||||
bin/build-linux-x64.sh
|
cp -r $SRC_DIR ./dist/trilium-linux-x64-src
|
||||||
|
cp -r $SRC_DIR ./dist/trilium-linux-x64-server
|
||||||
|
cp -r $SRC_DIR ./dist/trilium-windows-x64-src
|
||||||
|
cp -r $SRC_DIR ./dist/trilium-mac-x64-src
|
||||||
|
|
||||||
# this needs to be run after linux build
|
bin/build-win-x64.sh DONTCOPY
|
||||||
bin/build-debian.sh
|
|
||||||
|
|
||||||
bin/build-server.sh
|
bin/build-mac-x64.sh DONTCOPY
|
||||||
|
|
||||||
|
bin/build-linux-x64.sh DONTCOPY
|
||||||
|
|
||||||
|
bin/build-server.sh DONTCOPY
|
||||||
|
|||||||
32
bin/copy-trilium.sh
Executable file
32
bin/copy-trilium.sh
Executable 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
|
||||||
BIN
bin/deps/linux-x64/spellchecker/hunspell.a
Normal file
BIN
bin/deps/linux-x64/spellchecker/hunspell.a
Normal file
Binary file not shown.
BIN
bin/deps/linux-x64/spellchecker/spellchecker.node
Normal file
BIN
bin/deps/linux-x64/spellchecker/spellchecker.node
Normal file
Binary file not shown.
BIN
bin/deps/mac-x64/keyboard-layout-manager.node
Normal file
BIN
bin/deps/mac-x64/keyboard-layout-manager.node
Normal file
Binary file not shown.
BIN
bin/deps/mac-x64/spellchecker/hunspell.a
Normal file
BIN
bin/deps/mac-x64/spellchecker/hunspell.a
Normal file
Binary file not shown.
BIN
bin/deps/mac-x64/spellchecker/spellchecker.node
Normal file
BIN
bin/deps/mac-x64/spellchecker/spellchecker.node
Normal file
Binary file not shown.
BIN
bin/deps/win-x64/keyboard-layout-manager.node
Executable file
BIN
bin/deps/win-x64/keyboard-layout-manager.node
Executable file
Binary file not shown.
BIN
bin/deps/win-x64/spellchecker/hunspell.lib
Executable file
BIN
bin/deps/win-x64/spellchecker/hunspell.lib
Executable file
Binary file not shown.
BIN
bin/deps/win-x64/spellchecker/spellchecker.lib
Executable file
BIN
bin/deps/win-x64/spellchecker/spellchecker.lib
Executable file
Binary file not shown.
BIN
bin/deps/win-x64/spellchecker/spellchecker.node
Executable file
BIN
bin/deps/win-x64/spellchecker/spellchecker.node
Executable file
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
./node_modules/.bin/electron-rebuild --arch=x64
|
|
||||||
BIN
db/demo.tar
BIN
db/demo.tar
Binary file not shown.
5
db/migrations/0146__add_spell_check_options.sql
Normal file
5
db/migrations/0146__add_spell_check_options.sql
Normal 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);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced)
|
||||||
|
SELECT 'hideTabRowForOneTab', 'false', '2019-05-01T18:31:00.874Z', '2019-05-01T18:31:00.874Z', 0
|
||||||
|
WHERE NOT EXISTS(SELECT 1 FROM options WHERE name = 'hideTabRowForOneTab');
|
||||||
22
db/migrations/0148__make_isExpanded_not_null.sql
Normal file
22
db/migrations/0148__make_isExpanded_not_null.sql
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS "mig_branches" (
|
||||||
|
`branchId` TEXT NOT NULL,
|
||||||
|
`noteId` TEXT NOT NULL,
|
||||||
|
`parentNoteId` TEXT NOT NULL,
|
||||||
|
`notePosition` INTEGER NOT NULL,
|
||||||
|
`prefix` TEXT,
|
||||||
|
`isExpanded` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`isDeleted` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`utcDateModified` TEXT NOT NULL,
|
||||||
|
utcDateCreated TEXT NOT NULL,
|
||||||
|
hash TEXT DEFAULT "" NOT NULL,
|
||||||
|
PRIMARY KEY(`branchId`));
|
||||||
|
|
||||||
|
INSERT INTO mig_branches (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, utcDateModified, utcDateCreated, hash)
|
||||||
|
SELECT branchId, noteId, parentNoteId, notePosition, prefix, COALESCE(isExpanded, 0), isDeleted, utcDateModified, utcDateCreated, hash FROM branches;
|
||||||
|
|
||||||
|
DROP TABLE branches;
|
||||||
|
ALTER TABLE mig_branches RENAME TO branches;
|
||||||
|
|
||||||
|
CREATE INDEX `IDX_branches_noteId` ON `branches` (`noteId`);
|
||||||
|
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
||||||
|
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
||||||
2
db/migrations/0149__space_out_positions.sql
Normal file
2
db/migrations/0149__space_out_positions.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
UPDATE branches SET notePosition = notePosition * 10;
|
||||||
|
UPDATE attributes SET position = position * 10;
|
||||||
@@ -29,25 +29,6 @@ CREATE TABLE IF NOT EXISTS "api_tokens"
|
|||||||
utcDateCreated TEXT NOT NULL,
|
utcDateCreated TEXT NOT NULL,
|
||||||
isDeleted INT NOT NULL DEFAULT 0,
|
isDeleted INT NOT NULL DEFAULT 0,
|
||||||
hash TEXT DEFAULT "" NOT NULL);
|
hash TEXT DEFAULT "" NOT NULL);
|
||||||
CREATE TABLE IF NOT EXISTS "branches" (
|
|
||||||
`branchId` TEXT NOT NULL,
|
|
||||||
`noteId` TEXT NOT NULL,
|
|
||||||
`parentNoteId` TEXT NOT NULL,
|
|
||||||
`notePosition` INTEGER NOT NULL,
|
|
||||||
`prefix` TEXT,
|
|
||||||
`isExpanded` BOOLEAN,
|
|
||||||
`isDeleted` INTEGER NOT NULL DEFAULT 0,
|
|
||||||
`utcDateModified` TEXT NOT NULL,
|
|
||||||
utcDateCreated TEXT NOT NULL,
|
|
||||||
hash TEXT DEFAULT "" NOT NULL,
|
|
||||||
PRIMARY KEY(`branchId`)
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS "event_log" (
|
|
||||||
`eventId` TEXT NOT NULL PRIMARY KEY,
|
|
||||||
`noteId` TEXT,
|
|
||||||
`comment` TEXT,
|
|
||||||
`utcDateCreated` TEXT NOT NULL
|
|
||||||
);
|
|
||||||
CREATE TABLE IF NOT EXISTS "options"
|
CREATE TABLE IF NOT EXISTS "options"
|
||||||
(
|
(
|
||||||
name TEXT not null PRIMARY KEY,
|
name TEXT not null PRIMARY KEY,
|
||||||
@@ -84,21 +65,6 @@ CREATE TABLE IF NOT EXISTS "notes" (
|
|||||||
`utcDateModified` TEXT NOT NULL,
|
`utcDateModified` TEXT NOT NULL,
|
||||||
PRIMARY KEY(`noteId`)
|
PRIMARY KEY(`noteId`)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS "note_contents" (
|
|
||||||
`noteId` TEXT NOT NULL,
|
|
||||||
`content` TEXT NULL DEFAULT NULL,
|
|
||||||
`hash` TEXT DEFAULT "" NOT NULL,
|
|
||||||
`utcDateModified` TEXT NOT NULL,
|
|
||||||
PRIMARY KEY(`noteId`)
|
|
||||||
);
|
|
||||||
CREATE TABLE recent_notes
|
|
||||||
(
|
|
||||||
noteId TEXT not null primary key,
|
|
||||||
notePath TEXT not null,
|
|
||||||
hash TEXT default "" not null,
|
|
||||||
utcDateCreated TEXT not null,
|
|
||||||
isDeleted INT
|
|
||||||
);
|
|
||||||
CREATE UNIQUE INDEX `IDX_sync_entityName_entityId` ON `sync` (
|
CREATE UNIQUE INDEX `IDX_sync_entityName_entityId` ON `sync` (
|
||||||
`entityName`,
|
`entityName`,
|
||||||
`entityId`
|
`entityId`
|
||||||
@@ -115,14 +81,6 @@ CREATE INDEX `IDX_note_revisions_dateModifiedFrom` ON `note_revisions` (
|
|||||||
CREATE INDEX `IDX_note_revisions_dateModifiedTo` ON `note_revisions` (
|
CREATE INDEX `IDX_note_revisions_dateModifiedTo` ON `note_revisions` (
|
||||||
`utcDateModifiedTo`
|
`utcDateModifiedTo`
|
||||||
);
|
);
|
||||||
CREATE INDEX `IDX_branches_noteId` ON `branches` (
|
|
||||||
`noteId`
|
|
||||||
);
|
|
||||||
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (
|
|
||||||
`noteId`,
|
|
||||||
`parentNoteId`
|
|
||||||
);
|
|
||||||
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
|
||||||
CREATE INDEX IDX_attributes_name_value
|
CREATE INDEX IDX_attributes_name_value
|
||||||
on attributes (name, value);
|
on attributes (name, value);
|
||||||
CREATE INDEX IDX_attributes_name_index
|
CREATE INDEX IDX_attributes_name_index
|
||||||
@@ -131,3 +89,33 @@ CREATE INDEX IDX_attributes_noteId_index
|
|||||||
on attributes (noteId);
|
on attributes (noteId);
|
||||||
CREATE INDEX IDX_attributes_value_index
|
CREATE INDEX IDX_attributes_value_index
|
||||||
on attributes (value);
|
on attributes (value);
|
||||||
|
CREATE TABLE IF NOT EXISTS "note_contents" (
|
||||||
|
`noteId` TEXT NOT NULL,
|
||||||
|
`content` TEXT NULL DEFAULT NULL,
|
||||||
|
`hash` TEXT DEFAULT "" NOT NULL,
|
||||||
|
`utcDateModified` TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(`noteId`)
|
||||||
|
);
|
||||||
|
CREATE TABLE recent_notes
|
||||||
|
(
|
||||||
|
noteId TEXT not null primary key,
|
||||||
|
notePath TEXT not null,
|
||||||
|
hash TEXT default "" not null,
|
||||||
|
utcDateCreated TEXT not null,
|
||||||
|
isDeleted INT
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS "branches" (
|
||||||
|
`branchId` TEXT NOT NULL,
|
||||||
|
`noteId` TEXT NOT NULL,
|
||||||
|
`parentNoteId` TEXT NOT NULL,
|
||||||
|
`notePosition` INTEGER NOT NULL,
|
||||||
|
`prefix` TEXT,
|
||||||
|
`isExpanded` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`isDeleted` INTEGER NOT NULL DEFAULT 0,
|
||||||
|
`utcDateModified` TEXT NOT NULL,
|
||||||
|
utcDateCreated TEXT NOT NULL,
|
||||||
|
hash TEXT DEFAULT "" NOT NULL,
|
||||||
|
PRIMARY KEY(`branchId`));
|
||||||
|
CREATE INDEX `IDX_branches_noteId` ON `branches` (`noteId`);
|
||||||
|
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
||||||
|
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ the backend.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line310">line 310</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line312">line 312</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1533,7 +1533,7 @@ the backend.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line315">line 315</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line317">line 317</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1997,7 +1997,7 @@ the backend.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line239">line 239</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line241">line 241</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2765,7 +2765,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line258">line 258</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line260">line 260</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3418,7 +3418,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line230">line 230</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line232">line 232</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3596,7 +3596,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line249">line 249</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line251">line 251</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3751,7 +3751,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line267">line 267</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line269">line 269</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3901,7 +3901,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line222">line 222</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line224">line 224</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4427,7 +4427,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line287">line 287</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line289">line 289</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4560,7 +4560,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line274">line 274</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line276">line 276</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4935,7 +4935,7 @@ transactional by default.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line300">line 300</a>
|
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line302">line 302</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class Branch extends Entity {
|
|||||||
async beforeSaving() {
|
async beforeSaving() {
|
||||||
if (this.notePosition === undefined) {
|
if (this.notePosition === undefined) {
|
||||||
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
|
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
|
||||||
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 1;
|
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isDeleted) {
|
if (!this.isDeleted) {
|
||||||
|
|||||||
@@ -237,9 +237,11 @@ function BackendScriptApi(currentNote, apiParams) {
|
|||||||
* @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
|
* @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
|
||||||
*/
|
*/
|
||||||
this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) {
|
this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) {
|
||||||
await noteService.createNote(parentNoteId, title, content, extraOptions);
|
const ret = await noteService.createNote(parentNoteId, title, content, extraOptions);
|
||||||
|
|
||||||
ws.refreshTree();
|
ws.refreshTree();
|
||||||
|
|
||||||
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -343,7 +345,8 @@ function BackendScriptApi(currentNote, apiParams) {
|
|||||||
this.getAppInfo = () => appInfo
|
this.getAppInfo = () => appInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BackendScriptApi;</code></pre>
|
module.exports = BackendScriptApi;
|
||||||
|
</code></pre>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line19">line 19</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line21">line 21</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -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#line25">line 25</a>
|
||||||
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="currentNote"><span class="type-signature"></span>currentNote<span class="type-signature"></span></h4>
|
<h4 class="name" id="currentNote"><span class="type-signature"></span>currentNote<span class="type-signature"></span></h4>
|
||||||
|
|
||||||
|
|
||||||
@@ -223,7 +333,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line25">line 25</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line30">line 30</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -336,7 +446,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line27">line 27</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line32">line 32</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -442,7 +552,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line36">line 36</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line41">line 41</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -552,7 +662,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line23">line 23</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line28">line 28</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -661,7 +771,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line33">line 33</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line38">line 38</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -790,7 +900,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line61">line 61</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line66">line 66</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -945,7 +1055,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line45">line 45</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line50">line 50</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1100,7 +1210,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line80">line 80</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line85">line 85</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1280,7 +1390,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line269">line 269</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line279">line 279</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1413,7 +1523,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line229">line 229</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line239">line 239</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1471,7 +1581,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="getActiveNote"><span class="type-signature"></span>getActiveNote<span class="signature">()</span><span class="type-signature"> → {<a href="NoteFull.html">NoteFull</a>}</span></h4>
|
<h4 class="name" id="getActiveTabNote"><span class="type-signature"></span>getActiveTabNote<span class="signature">()</span><span class="type-signature"> → {<a href="NoteFull.html">NoteFull</a>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1519,7 +1629,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line275">line 275</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line285">line 285</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1577,7 +1687,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="getActiveNotePath"><span class="type-signature"></span>getActiveNotePath<span class="signature">()</span><span class="type-signature"> → {Promise.<(string|null)>}</span></h4>
|
<h4 class="name" id="getActiveTabNotePath"><span class="type-signature"></span>getActiveTabNotePath<span class="signature">()</span><span class="type-signature"> → {Promise.<(string|null)>}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1625,7 +1735,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line281">line 281</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line291">line 291</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1784,7 +1894,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line332">line 332</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line338">line 338</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1891,7 +2001,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line222">line 222</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line232">line 232</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2046,7 +2156,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line341">line 341</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line347">line 347</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2202,7 +2312,7 @@ if some action needs to happen on only one specific instance.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line190">line 190</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line200">line 200</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2403,7 +2513,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line202">line 202</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line212">line 212</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2509,7 +2619,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line323">line 323</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line329">line 329</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2664,7 +2774,7 @@ otherwise (by e.g. createNoteLink())
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line350">line 350</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line356">line 356</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2773,7 +2883,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line296">line 296</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line302">line 302</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2928,7 +3038,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line304">line 304</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line310">line 310</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3061,7 +3171,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line236">line 236</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line246">line 246</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3167,7 +3277,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line315">line 315</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line321">line 321</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3255,7 +3365,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line260">line 260</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line270">line 270</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3309,7 +3419,7 @@ note.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="reloadChildren"><span class="type-signature"></span>reloadChildren<span class="signature">(noteId)</span><span class="type-signature"></span></h4>
|
<h4 class="name" id="reloadNotesAndTheirChildren"><span class="type-signature"></span>reloadNotesAndTheirChildren<span class="signature">(noteId)</span><span class="type-signature"></span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -3406,7 +3516,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line208">line 208</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line218">line 218</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3539,7 +3649,7 @@ note.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line214">line 214</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line224">line 224</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3700,7 +3810,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line130">line 130</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line135">line 135</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3860,7 +3970,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line178">line 178</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line188">line 188</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4016,7 +4126,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line160">line 160</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line170">line 170</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4070,6 +4180,161 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h4 class="name" id="setHoistedNoteId"><span class="type-signature"></span>setHoistedNoteId<span class="signature">(noteId)</span><span class="type-signature"> → {Promise}</span></h4>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
Hoist note. See https://github.com/zadam/trilium/wiki/Note-hoisting
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Parameters:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="params">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<th>Name</th>
|
||||||
|
|
||||||
|
|
||||||
|
<th>Type</th>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<th class="last">Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
|
||||||
|
<td class="name"><code>noteId</code></td>
|
||||||
|
|
||||||
|
|
||||||
|
<td class="type">
|
||||||
|
|
||||||
|
|
||||||
|
<span class="param-type">string</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<td class="description last">set hoisted note. 'root' will effectively unhoist</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#line365">line 365</a>
|
||||||
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h5>Returns:</h5>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>
|
||||||
|
Type
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
|
||||||
|
<span class="param-type">Promise</span>
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 class="name" id="setupElementTooltip"><span class="type-signature"></span>setupElementTooltip<span class="signature">($el)</span><span class="type-signature"></span></h4>
|
<h4 class="name" id="setupElementTooltip"><span class="type-signature"></span>setupElementTooltip<span class="signature">($el)</span><span class="type-signature"></span></h4>
|
||||||
|
|
||||||
|
|
||||||
@@ -4167,7 +4432,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line310">line 310</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line316">line 316</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4304,7 +4569,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line252">line 252</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line262">line 262</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4441,7 +4706,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line244">line 244</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line254">line 254</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,10 @@
|
|||||||
|
|
||||||
<h2><span class="attribs"><span class="type-signature"></span></span>NoteShort<span class="signature">()</span><span class="type-signature"></span></h2>
|
<h2><span class="attribs"><span class="type-signature"></span></span>NoteShort<span class="signature">()</span><span class="type-signature"></span></h2>
|
||||||
|
|
||||||
<div class="class-description">This note's representation is used in note tree and is kept in TreeCache.</div>
|
<div class="class-description">FIXME: rethink how attributes are cached in Note entities since they are long lived inside the cache.
|
||||||
|
Attribute cache should be limited to "transaction".
|
||||||
|
|
||||||
|
This note's representation is used in note tree and is kept in TreeCache.</div>
|
||||||
|
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
@@ -93,7 +96,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line13">line 13</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line16">line 16</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -183,7 +186,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line26">line 26</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line29">line 29</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -241,7 +244,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line28">line 28</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line31">line 31</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line20">line 20</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line23">line 23</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -357,7 +360,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line24">line 24</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line27">line 27</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -415,7 +418,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line16">line 16</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line19">line 19</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -473,7 +476,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line18">line 18</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line21">line 21</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -531,7 +534,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line22">line 22</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line25">line 25</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -679,7 +682,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line166">line 166</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line169">line 169</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -846,7 +849,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line106">line 106</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line109">line 109</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1020,7 +1023,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line177">line 177</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line180">line 180</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1126,7 +1129,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line57">line 57</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line60">line 60</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1228,7 +1231,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line71">line 71</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line74">line 74</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1330,7 +1333,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line93">line 93</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line96">line 96</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1432,7 +1435,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line98">line 98</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line101">line 101</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1583,7 +1586,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line199">line 199</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line202">line 202</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1750,7 +1753,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line132">line 132</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line135">line 135</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -1917,7 +1920,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line124">line 124</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line127">line 127</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2072,7 +2075,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line211">line 211</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line214">line 214</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2178,7 +2181,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line83">line 83</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line86">line 86</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2280,7 +2283,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line88">line 88</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line91">line 91</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2431,7 +2434,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line205">line 205</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line208">line 208</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2598,7 +2601,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line148">line 148</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line151">line 151</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2765,7 +2768,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line140">line 140</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line143">line 143</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -2920,7 +2923,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line223">line 223</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line226">line 226</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3090,7 +3093,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line233">line 233</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line236">line 236</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3241,7 +3244,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line217">line 217</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line220">line 220</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3351,7 +3354,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line257">line 257</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line260">line 260</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3525,7 +3528,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line157">line 157</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line160">line 160</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3631,7 +3634,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line65">line 65</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line68">line 68</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3782,7 +3785,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line187">line 187</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line190">line 190</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -3937,7 +3940,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line193">line 193</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line196">line 196</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4048,7 +4051,7 @@ Cache is note instance scoped.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line248">line 248</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line251">line 251</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
@@ -4132,7 +4135,7 @@ Cache is note instance scoped.
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line32">line 32</a>
|
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line35">line 35</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ const RELATION = 'relation';
|
|||||||
const RELATION_DEFINITION = 'relation-definition';
|
const RELATION_DEFINITION = 'relation-definition';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* FIXME: rethink how attributes are cached in Note entities since they are long lived inside the cache.
|
||||||
|
* Attribute cache should be limited to "transaction".
|
||||||
|
*
|
||||||
* This note's representation is used in note tree and is kept in TreeCache.
|
* This note's representation is used in note tree and is kept in TreeCache.
|
||||||
*/
|
*/
|
||||||
class NoteShort {
|
class NoteShort {
|
||||||
|
|||||||
@@ -303,7 +303,7 @@
|
|||||||
|
|
||||||
<dt class="tag-source">Source:</dt>
|
<dt class="tag-source">Source:</dt>
|
||||||
<dd class="tag-source"><ul class="dummy"><li>
|
<dd class="tag-source"><ul class="dummy"><li>
|
||||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line67">line 67</a>
|
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line72">line 72</a>
|
||||||
</li></ul></dd>
|
</li></ul></dd>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<pre class="prettyprint source linenums"><code>import treeService from './tree.js';
|
<pre class="prettyprint source linenums"><code>import treeService from './tree.js';
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import infoService from './info.js';
|
import toastService from './toast.js';
|
||||||
import linkService from './link.js';
|
import linkService from './link.js';
|
||||||
import treeCache from './tree_cache.js';
|
import treeCache from './tree_cache.js';
|
||||||
import noteDetailService from './note_detail.js';
|
import noteDetailService from './note_detail.js';
|
||||||
@@ -37,6 +37,8 @@ import noteTooltipService from './note_tooltip.js';
|
|||||||
import protectedSessionService from './protected_session.js';
|
import protectedSessionService from './protected_session.js';
|
||||||
import dateNotesService from './date_notes.js';
|
import dateNotesService from './date_notes.js';
|
||||||
import StandardWidget from '../widgets/standard_widget.js';
|
import StandardWidget from '../widgets/standard_widget.js';
|
||||||
|
import ws from "./ws.js";
|
||||||
|
import hoistedNoteService from "./hoisted_note.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
||||||
@@ -44,9 +46,12 @@ import StandardWidget from '../widgets/standard_widget.js';
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @hideconstructor
|
* @hideconstructor
|
||||||
*/
|
*/
|
||||||
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) {
|
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
|
||||||
const $pluginButtons = $("#plugin-buttons");
|
const $pluginButtons = $("#plugin-buttons");
|
||||||
|
|
||||||
|
/** @property {jQuery} container of all the rendered script content */
|
||||||
|
this.$container = $container;
|
||||||
|
|
||||||
/** @property {object} note where script started executing */
|
/** @property {object} note where script started executing */
|
||||||
this.startNote = startNote;
|
this.startNote = startNote;
|
||||||
/** @property {object} note where script is currently executing */
|
/** @property {object} note where script is currently executing */
|
||||||
@@ -167,9 +172,14 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
currentNoteId: currentNote.noteId,
|
currentNoteId: currentNote.noteId,
|
||||||
originEntityName: "notes", // currently there's no other entity on frontend which can trigger event
|
originEntityName: "notes", // currently there's no other entity on frontend which can trigger event
|
||||||
originEntityId: originEntity ? originEntity.noteId : null
|
originEntityId: originEntity ? originEntity.noteId : null
|
||||||
|
}, {
|
||||||
|
'trilium-source-id': "script"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ret.success) {
|
if (ret.success) {
|
||||||
|
// wait until all the changes done in the script has been synced to frontend before continuing
|
||||||
|
await ws.waitForSyncId(ret.maxSyncId);
|
||||||
|
|
||||||
return ret.executionResult;
|
return ret.executionResult;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -233,7 +243,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @param {string} noteId
|
* @param {string} noteId
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
this.reloadChildren = async noteId => await treeCache.reloadChildren(noteId);
|
this.reloadNotesAndTheirChildren = async noteId => await treeCache.reloadNotesAndTheirChildren(noteId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} noteId
|
* @param {string} noteId
|
||||||
@@ -269,7 +279,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
this.showMessage = infoService.showMessage;
|
this.showMessage = toastService.showMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show error message to the user.
|
* Show error message to the user.
|
||||||
@@ -277,7 +287,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
this.showError = infoService.showError;
|
this.showError = toastService.showError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh tree
|
* Refresh tree
|
||||||
@@ -300,17 +310,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @returns {NoteFull} active note (loaded into right pane)
|
* @returns {NoteFull} active note (loaded into right pane)
|
||||||
*/
|
*/
|
||||||
this.getActiveNote = noteDetailService.getActiveNote;
|
this.getActiveTabNote = noteDetailService.getActiveTabNote;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
||||||
*/
|
*/
|
||||||
this.getActiveNotePath = () => {
|
this.getActiveTabNotePath = noteDetailService.getActiveTabNotePath;
|
||||||
const activeTabContext = noteDetailService.getActiveTabContext();
|
|
||||||
|
|
||||||
return activeTabContext ? activeTabContext.notePath : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method checks whether user navigated away from the note from which the scripts has been started.
|
* This method checks whether user navigated away from the note from which the scripts has been started.
|
||||||
@@ -322,7 +328,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @return {boolean} returns true if the original note is still loaded, false if user switched to another
|
* @return {boolean} returns true if the original note is still loaded, false if user switched to another
|
||||||
*/
|
*/
|
||||||
this.isNoteStillActive = () => {
|
this.isNoteStillActive = () => {
|
||||||
return this.originEntity.noteId === tabContext.noteId;
|
return tabContext.note && this.originEntity.noteId === tabContext.note.noteId;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -376,6 +382,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @return {Promise<NoteShort>}
|
* @return {Promise<NoteShort>}
|
||||||
*/
|
*/
|
||||||
this.getYearNote = dateNotesService.getYearNote;
|
this.getYearNote = dateNotesService.getYearNote;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hoist note. See https://github.com/zadam/trilium/wiki/Note-hoisting
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @param {string} noteId - set hoisted note. 'root' will effectively unhoist
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
this.setHoistedNoteId = hoistedNoteService.setHoistedNoteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FrontendScriptApi;</code></pre>
|
export default FrontendScriptApi;</code></pre>
|
||||||
|
|||||||
46
electron.js
46
electron.js
@@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const electron = require('electron');
|
const {app, globalShortcut, BrowserWindow} = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const log = require('./src/services/log');
|
const log = require('./src/services/log');
|
||||||
const sqlInit = require('./src/services/sql_init');
|
const sqlInit = require('./src/services/sql_init');
|
||||||
@@ -10,10 +10,6 @@ const port = require('./src/services/port');
|
|||||||
const env = require('./src/services/env');
|
const env = require('./src/services/env');
|
||||||
const appIconService = require('./src/services/app_icon');
|
const appIconService = require('./src/services/app_icon');
|
||||||
const windowStateKeeper = require('electron-window-state');
|
const windowStateKeeper = require('electron-window-state');
|
||||||
const contextMenu = require('electron-context-menu');
|
|
||||||
|
|
||||||
const app = electron.app;
|
|
||||||
const globalShortcut = electron.globalShortcut;
|
|
||||||
|
|
||||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||||
require('electron-debug')();
|
require('electron-debug')();
|
||||||
@@ -25,25 +21,25 @@ let mainWindow;
|
|||||||
|
|
||||||
require('electron-dl')({ saveAs: true });
|
require('electron-dl')({ saveAs: true });
|
||||||
|
|
||||||
contextMenu({
|
// contextMenu({
|
||||||
menu: (actions, params, browserWindow) => [
|
// menu: (actions, params, browserWindow) => [
|
||||||
actions.cut(),
|
// actions.cut(),
|
||||||
actions.copy(),
|
// actions.copy(),
|
||||||
actions.copyLink(),
|
// actions.copyLink(),
|
||||||
actions.paste(),
|
// actions.paste(),
|
||||||
{
|
// {
|
||||||
label: 'Search DuckDuckGo for “{selection}”',
|
// label: 'Search DuckDuckGo for “{selection}”',
|
||||||
// Only show it when right-clicking text
|
// // Only show it when right-clicking text
|
||||||
visible: params.selectionText.trim().length > 0,
|
// visible: params.selectionText.trim().length > 0,
|
||||||
click: () => {
|
// click: () => {
|
||||||
const {shell} = require('electron');
|
// const {shell} = require('electron');
|
||||||
|
//
|
||||||
shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`);
|
// shell.openExternal(`https://duckduckgo.com?q=${encodeURIComponent(params.selectionText)}`);
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
actions.inspect()
|
// actions.inspect()
|
||||||
]
|
// ]
|
||||||
});
|
// });
|
||||||
|
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
// Dereference the window
|
// Dereference the window
|
||||||
@@ -66,7 +62,7 @@ async function createMainWindow() {
|
|||||||
defaultHeight: 800
|
defaultHeight: 800
|
||||||
});
|
});
|
||||||
|
|
||||||
const win = new electron.BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
x: mainWindowState.x,
|
x: mainWindowState.x,
|
||||||
y: mainWindowState.y,
|
y: mainWindowState.y,
|
||||||
width: mainWindowState.width,
|
width: mainWindowState.width,
|
||||||
|
|||||||
2
libraries/bootstrap-notify.min.js
vendored
2
libraries/bootstrap-notify.min.js
vendored
File diff suppressed because one or more lines are too long
4
libraries/codemirror/addon/lint/eslint.js
vendored
4
libraries/codemirror/addon/lint/eslint.js
vendored
@@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
async function validatorJavaScript(text, options) {
|
async function validatorJavaScript(text, options) {
|
||||||
if (glob.isMobile()
|
if (glob.isMobile()
|
||||||
|| glob.getActiveNote() == null
|
|| glob.getActiveTabNote() == null
|
||||||
|| glob.getActiveNote().mime === 'application/json') {
|
|| glob.getActiveTabNote().mime === 'application/json') {
|
||||||
// eslint doesn't seem to validate pure JSON well
|
// eslint doesn't seem to validate pure JSON well
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
4682
package-lock.json
generated
4682
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
25
package.json
25
package.json
@@ -2,7 +2,7 @@
|
|||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"productName": "Trilium Notes",
|
"productName": "Trilium Notes",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.35.1",
|
"version": "0.36.1-beta",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -17,8 +17,7 @@
|
|||||||
"start-electron": "TRILIUM_ENV=dev electron . --disable-gpu",
|
"start-electron": "TRILIUM_ENV=dev electron . --disable-gpu",
|
||||||
"build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
|
"build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
|
||||||
"build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
|
"build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
|
||||||
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
|
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs"
|
||||||
"postinstall": "electron-builder install-app-deps"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-mutex": "0.1.4",
|
"async-mutex": "0.1.4",
|
||||||
@@ -31,32 +30,32 @@
|
|||||||
"dayjs": "1.8.16",
|
"dayjs": "1.8.16",
|
||||||
"debug": "4.1.1",
|
"debug": "4.1.1",
|
||||||
"ejs": "2.7.1",
|
"ejs": "2.7.1",
|
||||||
"electron-context-menu": "0.15.0",
|
|
||||||
"electron-debug": "3.0.1",
|
"electron-debug": "3.0.1",
|
||||||
"electron-dl": "1.14.0",
|
"electron-dl": "1.14.0",
|
||||||
"electron-find": "1.0.6",
|
"electron-find": "1.0.6",
|
||||||
|
"electron-spellchecker": "2.2.0",
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"express": "4.17.1",
|
"express": "4.17.1",
|
||||||
"express-session": "1.16.2",
|
"express-session": "1.17.0",
|
||||||
"file-type": "12.3.0",
|
"file-type": "12.3.0",
|
||||||
"fs-extra": "8.1.0",
|
"fs-extra": "8.1.0",
|
||||||
"helmet": "3.21.1",
|
"helmet": "3.21.1",
|
||||||
"html": "1.0.0",
|
"html": "1.0.0",
|
||||||
"html2plaintext": "2.1.2",
|
"html2plaintext": "2.1.2",
|
||||||
"http-proxy-agent": "^2.1.0",
|
"http-proxy-agent": "2.1.0",
|
||||||
"https-proxy-agent": "^2.2.2",
|
"https-proxy-agent": "3.0.0",
|
||||||
"image-type": "4.1.0",
|
"image-type": "4.1.0",
|
||||||
"imagemin": "7.0.0",
|
"imagemin": "7.0.0",
|
||||||
"imagemin-giflossy": "5.1.10",
|
"imagemin-giflossy": "5.1.10",
|
||||||
"imagemin-mozjpeg": "8.0.0",
|
"imagemin-mozjpeg": "8.0.0",
|
||||||
"imagemin-pngquant": "8.0.0",
|
"imagemin-pngquant": "8.0.0",
|
||||||
"ini": "1.3.5",
|
"ini": "1.3.5",
|
||||||
"jimp": "0.8.4",
|
"jimp": "0.8.5",
|
||||||
"mime-types": "2.1.24",
|
"mime-types": "2.1.24",
|
||||||
"moment": "2.24.0",
|
"moment": "2.24.0",
|
||||||
"multer": "1.4.2",
|
"multer": "1.4.2",
|
||||||
"node-abi": "2.11.0",
|
"node-abi": "2.11.0",
|
||||||
"open": "6.4.0",
|
"open": "7.0.0",
|
||||||
"pngjs": "3.4.0",
|
"pngjs": "3.4.0",
|
||||||
"portscanner": "2.2.0",
|
"portscanner": "2.2.0",
|
||||||
"rand-token": "0.4.0",
|
"rand-token": "0.4.0",
|
||||||
@@ -70,22 +69,22 @@
|
|||||||
"simple-node-logger": "18.12.23",
|
"simple-node-logger": "18.12.23",
|
||||||
"sqlite": "3.0.3",
|
"sqlite": "3.0.3",
|
||||||
"sqlite3": "4.1.0",
|
"sqlite3": "4.1.0",
|
||||||
"string-similarity": "^3.0.0",
|
"string-similarity": "3.0.0",
|
||||||
"tar-stream": "2.1.0",
|
"tar-stream": "2.1.0",
|
||||||
"turndown": "5.0.3",
|
"turndown": "5.0.3",
|
||||||
"turndown-plugin-gfm": "1.0.2",
|
"turndown-plugin-gfm": "1.0.2",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"ws": "7.1.2",
|
"ws": "7.2.0",
|
||||||
"xml2js": "0.4.22"
|
"xml2js": "0.4.22"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "6.0.10",
|
"electron": "6.0.12",
|
||||||
"electron-builder": "21.2.0",
|
"electron-builder": "21.2.0",
|
||||||
"electron-compile": "6.4.4",
|
"electron-compile": "6.4.4",
|
||||||
"electron-installer-debian": "2.0.1",
|
"electron-installer-debian": "2.0.1",
|
||||||
"electron-packager": "14.0.6",
|
"electron-packager": "14.0.6",
|
||||||
"electron-rebuild": "1.8.6",
|
"electron-rebuild": "1.8.6",
|
||||||
"jsdoc": "^3.6.3",
|
"jsdoc": "3.6.3",
|
||||||
"lorem-ipsum": "2.0.3",
|
"lorem-ipsum": "2.0.3",
|
||||||
"xo": "0.25.3"
|
"xo": "0.25.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ app.use((req, res, next) => {
|
|||||||
|
|
||||||
// error handler
|
// error handler
|
||||||
app.use((err, req, res, next) => {
|
app.use((err, req, res, next) => {
|
||||||
if (err && err.message && err.message.includes("Invalid package")) {
|
if (err && err.message && (
|
||||||
|
err.message.includes("Invalid package")
|
||||||
|
|| (err.message.includes("Router not found for request") && err.message.includes("node_modules"))
|
||||||
|
)) {
|
||||||
// electron 6 outputs a lot of such errors which do not seem important
|
// electron 6 outputs a lot of such errors which do not seem important
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Branch extends Entity {
|
|||||||
async beforeSaving() {
|
async beforeSaving() {
|
||||||
if (this.notePosition === undefined) {
|
if (this.notePosition === undefined) {
|
||||||
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
|
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [this.parentNoteId]);
|
||||||
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 1;
|
this.notePosition = maxNotePos === null ? 0 : maxNotePos + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isDeleted) {
|
if (!this.isDeleted) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import macInit from './services/mac_init.js';
|
|||||||
import cssLoader from './services/css_loader.js';
|
import cssLoader from './services/css_loader.js';
|
||||||
import dateNoteService from './services/date_notes.js';
|
import dateNoteService from './services/date_notes.js';
|
||||||
import sidebarService from './services/sidebar.js';
|
import sidebarService from './services/sidebar.js';
|
||||||
|
import importService from './services/import.js';
|
||||||
|
|
||||||
window.glob.isDesktop = utils.isDesktop;
|
window.glob.isDesktop = utils.isDesktop;
|
||||||
window.glob.isMobile = utils.isMobile;
|
window.glob.isMobile = utils.isMobile;
|
||||||
@@ -42,7 +43,7 @@ window.glob.noteChanged = noteDetailService.noteChanged;
|
|||||||
window.glob.refreshTree = treeService.reload;
|
window.glob.refreshTree = treeService.reload;
|
||||||
|
|
||||||
// required for ESLint plugin
|
// required for ESLint plugin
|
||||||
window.glob.getActiveNote = noteDetailService.getActiveNote;
|
window.glob.getActiveTabNote = noteDetailService.getActiveTabNote;
|
||||||
window.glob.requireLibrary = libraryLoader.requireLibrary;
|
window.glob.requireLibrary = libraryLoader.requireLibrary;
|
||||||
window.glob.ESLINT = libraryLoader.ESLINT;
|
window.glob.ESLINT = libraryLoader.ESLINT;
|
||||||
|
|
||||||
@@ -177,3 +178,7 @@ entrypoints.registerEntrypoints();
|
|||||||
noteTooltipService.setupGlobalTooltip();
|
noteTooltipService.setupGlobalTooltip();
|
||||||
|
|
||||||
noteAutocompleteService.init();
|
noteAutocompleteService.init();
|
||||||
|
|
||||||
|
if (utils.isElectron()) {
|
||||||
|
import("./services/spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ export async function showDialog(linkType) {
|
|||||||
|
|
||||||
glob.activeDialog = $dialog;
|
glob.activeDialog = $dialog;
|
||||||
|
|
||||||
if (noteDetailService.getActiveNoteType() === 'text') {
|
if (noteDetailService.getActiveTabNoteType() === 'text') {
|
||||||
$linkTypeHtml.prop('disabled', false);
|
$linkTypeHtml.prop('disabled', false);
|
||||||
|
|
||||||
setLinkType('html');
|
setLinkType('html');
|
||||||
@@ -110,14 +110,14 @@ $form.submit(() => {
|
|||||||
else if (linkType === 'selected-to-active') {
|
else if (linkType === 'selected-to-active') {
|
||||||
const prefix = $clonePrefix.val();
|
const prefix = $clonePrefix.val();
|
||||||
|
|
||||||
cloningService.cloneNoteTo(noteId, noteDetailService.getActiveNoteId(), prefix);
|
cloningService.cloneNoteTo(noteId, noteDetailService.getActiveTabNoteId(), prefix);
|
||||||
|
|
||||||
$dialog.modal('hide');
|
$dialog.modal('hide');
|
||||||
}
|
}
|
||||||
else if (linkType === 'active-to-selected') {
|
else if (linkType === 'active-to-selected') {
|
||||||
const prefix = $clonePrefix.val();
|
const prefix = $clonePrefix.val();
|
||||||
|
|
||||||
cloningService.cloneNoteTo(noteDetailService.getActiveNoteId(), noteId, prefix);
|
cloningService.cloneNoteTo(noteDetailService.getActiveTabNoteId(), noteId, prefix);
|
||||||
|
|
||||||
$dialog.modal('hide');
|
$dialog.modal('hide');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import noteDetailService from '../services/note_detail.js';
|
import noteDetailService from '../services/note_detail.js';
|
||||||
import server from '../services/server.js';
|
import server from '../services/server.js';
|
||||||
import infoService from "../services/info.js";
|
import toastService from "../services/toast.js";
|
||||||
import treeUtils from "../services/tree_utils.js";
|
import treeUtils from "../services/tree_utils.js";
|
||||||
import attributeAutocompleteService from "../services/attribute_autocomplete.js";
|
import attributeAutocompleteService from "../services/attribute_autocomplete.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
@@ -47,14 +47,15 @@ function AttributesModel() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.updateAttributePositions = function() {
|
this.updateAttributePositions = function() {
|
||||||
let position = 0;
|
let position = 10;
|
||||||
|
|
||||||
// we need to update positions by searching in the DOM, because order of the
|
// we need to update positions by searching in the DOM, because order of the
|
||||||
// attributes in the viewmodel (self.ownedAttributes()) stays the same
|
// attributes in the viewmodel (self.ownedAttributes()) stays the same
|
||||||
$ownedAttributesBody.find('input[name="position"]').each(function() {
|
$ownedAttributesBody.find('input[name="position"]').each(function() {
|
||||||
const attribute = self.getTargetAttribute(this);
|
const attribute = self.getTargetAttribute(this);
|
||||||
|
|
||||||
attribute().position = position++;
|
attribute().position = position;
|
||||||
|
position += 10;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,7 +92,7 @@ function AttributesModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.loadAttributes = async function() {
|
this.loadAttributes = async function() {
|
||||||
const noteId = noteDetailService.getActiveNoteId();
|
const noteId = noteDetailService.getActiveTabNoteId();
|
||||||
|
|
||||||
const attributes = await server.get('notes/' + noteId + '/attributes');
|
const attributes = await server.get('notes/' + noteId + '/attributes');
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ function AttributesModel() {
|
|||||||
|
|
||||||
self.updateAttributePositions();
|
self.updateAttributePositions();
|
||||||
|
|
||||||
const noteId = noteDetailService.getActiveNoteId();
|
const noteId = noteDetailService.getActiveTabNoteId();
|
||||||
|
|
||||||
const attributesToSave = self.ownedAttributes()
|
const attributesToSave = self.ownedAttributes()
|
||||||
.map(attribute => attribute())
|
.map(attribute => attribute())
|
||||||
@@ -167,7 +168,7 @@ function AttributesModel() {
|
|||||||
|
|
||||||
await showAttributes(attributes);
|
await showAttributes(attributes);
|
||||||
|
|
||||||
infoService.showMessage("Attributes have been saved.");
|
toastService.showMessage("Attributes have been saved.");
|
||||||
|
|
||||||
const ctx = noteDetailService.getActiveTabContext();
|
const ctx = noteDetailService.getActiveTabContext();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import treeService from '../services/tree.js';
|
|||||||
import server from '../services/server.js';
|
import server from '../services/server.js';
|
||||||
import treeCache from "../services/tree_cache.js";
|
import treeCache from "../services/tree_cache.js";
|
||||||
import treeUtils from "../services/tree_utils.js";
|
import treeUtils from "../services/tree_utils.js";
|
||||||
import infoService from "../services/info.js";
|
import toastService from "../services/toast.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
|
|
||||||
const $dialog = $("#branch-prefix-dialog");
|
const $dialog = $("#branch-prefix-dialog");
|
||||||
@@ -38,7 +38,7 @@ async function savePrefix() {
|
|||||||
|
|
||||||
$dialog.modal('hide');
|
$dialog.modal('hide');
|
||||||
|
|
||||||
infoService.showMessage("Branch prefix has been saved.");
|
toastService.showMessage("Branch prefix has been saved.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$form.submit(() => {
|
$form.submit(() => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import treeUtils from "../services/tree_utils.js";
|
import treeUtils from "../services/tree_utils.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import ws from "../services/ws.js";
|
import ws from "../services/ws.js";
|
||||||
import infoService from "../services/info.js";
|
import toastService from "../services/toast.js";
|
||||||
|
|
||||||
const $dialog = $("#export-dialog");
|
const $dialog = $("#export-dialog");
|
||||||
const $form = $("#export-form");
|
const $form = $("#export-form");
|
||||||
@@ -10,22 +10,18 @@ const $subtreeFormats = $("#export-subtree-formats");
|
|||||||
const $singleFormats = $("#export-single-formats");
|
const $singleFormats = $("#export-single-formats");
|
||||||
const $subtreeType = $("#export-type-subtree");
|
const $subtreeType = $("#export-type-subtree");
|
||||||
const $singleType = $("#export-type-single");
|
const $singleType = $("#export-type-single");
|
||||||
const $exportProgressWrapper = $("#export-progress-count-wrapper");
|
|
||||||
const $exportProgressCount = $("#export-progress-count");
|
|
||||||
const $exportButton = $("#export-button");
|
const $exportButton = $("#export-button");
|
||||||
const $opmlVersions = $("#opml-versions");
|
const $opmlVersions = $("#opml-versions");
|
||||||
|
|
||||||
let exportId = '';
|
let taskId = '';
|
||||||
let branchId = null;
|
let branchId = null;
|
||||||
|
|
||||||
export async function showDialog(node, defaultType) {
|
export async function showDialog(node, defaultType) {
|
||||||
utils.closeActiveDialog();
|
utils.closeActiveDialog();
|
||||||
|
|
||||||
// each opening of the dialog resets the exportId so we don't associate it with previous exports anymore
|
// each opening of the dialog resets the taskId so we don't associate it with previous exports anymore
|
||||||
exportId = '';
|
taskId = '';
|
||||||
$exportButton.removeAttr("disabled");
|
$exportButton.removeAttr("disabled");
|
||||||
$exportProgressWrapper.hide();
|
|
||||||
$exportProgressCount.text('0');
|
|
||||||
|
|
||||||
if (defaultType === 'subtree') {
|
if (defaultType === 'subtree') {
|
||||||
$subtreeType.prop("checked", true).change();
|
$subtreeType.prop("checked", true).change();
|
||||||
@@ -54,8 +50,7 @@ export async function showDialog(node, defaultType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$form.submit(() => {
|
$form.submit(() => {
|
||||||
// disabling so export can't be triggered again
|
$dialog.modal('hide');
|
||||||
$exportButton.attr("disabled", "disabled");
|
|
||||||
|
|
||||||
const exportType = $dialog.find("input[name='export-type']:checked").val();
|
const exportType = $dialog.find("input[name='export-type']:checked").val();
|
||||||
|
|
||||||
@@ -77,9 +72,9 @@ $form.submit(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function exportBranch(branchId, type, format, version) {
|
function exportBranch(branchId, type, format, version) {
|
||||||
exportId = utils.randomString(10);
|
taskId = utils.randomString(10);
|
||||||
|
|
||||||
const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}/${version}/${exportId}`;
|
const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`;
|
||||||
|
|
||||||
utils.download(url);
|
utils.download(url);
|
||||||
}
|
}
|
||||||
@@ -112,26 +107,31 @@ $('input[name=export-subtree-format]').change(function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function makeToast(id, message) {
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
title: "Export status",
|
||||||
|
message: message,
|
||||||
|
icon: "arrow-square-up-right"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ws.subscribeToMessages(async message => {
|
ws.subscribeToMessages(async message => {
|
||||||
if (message.type === 'export-error') {
|
if (message.taskType !== 'export') {
|
||||||
infoService.showError(message.message);
|
|
||||||
$dialog.modal('hide');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!message.exportId || message.exportId !== exportId) {
|
if (message.type === 'task-error') {
|
||||||
// incoming messages must correspond to this export instance
|
toastService.closePersistent(message.taskId);
|
||||||
return;
|
toastService.showError(message.message);
|
||||||
}
|
}
|
||||||
|
else if (message.type === 'task-progress-count') {
|
||||||
if (message.type === 'export-progress-count') {
|
toastService.showPersistent(makeToast(message.taskId, "Export in progress: " + message.progressCount));
|
||||||
$exportProgressWrapper.slideDown();
|
|
||||||
|
|
||||||
$exportProgressCount.text(message.progressCount);
|
|
||||||
}
|
}
|
||||||
else if (message.type === 'export-finished') {
|
else if (message.type === 'task-succeeded') {
|
||||||
$dialog.modal('hide');
|
const toast = makeToast(message.taskId, "Import finished successfully.");
|
||||||
|
toast.closeAfter = 5000;
|
||||||
|
|
||||||
infoService.showMessage("Export finished successfully.");
|
toastService.showPersistent(toast);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
import treeService from '../services/tree.js';
|
|
||||||
import utils from '../services/utils.js';
|
import utils from '../services/utils.js';
|
||||||
import treeUtils from "../services/tree_utils.js";
|
import treeUtils from "../services/tree_utils.js";
|
||||||
import server from "../services/server.js";
|
import importService from "../services/import.js";
|
||||||
import infoService from "../services/info.js";
|
|
||||||
import ws from "../services/ws.js";
|
|
||||||
|
|
||||||
const $dialog = $("#import-dialog");
|
const $dialog = $("#import-dialog");
|
||||||
const $form = $("#import-form");
|
const $form = $("#import-form");
|
||||||
const $noteTitle = $dialog.find(".import-note-title");
|
const $noteTitle = $dialog.find(".import-note-title");
|
||||||
const $fileUploadInput = $("#import-file-upload-input");
|
const $fileUploadInput = $("#import-file-upload-input");
|
||||||
const $importProgressCountWrapper = $("#import-progress-count-wrapper");
|
|
||||||
const $importProgressCount = $("#import-progress-count");
|
|
||||||
const $importButton = $("#import-button");
|
const $importButton = $("#import-button");
|
||||||
const $safeImportCheckbox = $("#safe-import-checkbox");
|
const $safeImportCheckbox = $("#safe-import-checkbox");
|
||||||
const $shrinkImagesCheckbox = $("#shrink-images-checkbox");
|
const $shrinkImagesCheckbox = $("#shrink-images-checkbox");
|
||||||
@@ -18,16 +13,11 @@ const $textImportedAsTextCheckbox = $("#text-imported-as-text-checkbox");
|
|||||||
const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox");
|
const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox");
|
||||||
const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
|
const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
|
||||||
|
|
||||||
let importId;
|
let parentNoteId = null;
|
||||||
let importIntoNoteId = null;
|
|
||||||
|
|
||||||
export async function showDialog(node) {
|
export async function showDialog(node) {
|
||||||
utils.closeActiveDialog();
|
utils.closeActiveDialog();
|
||||||
|
|
||||||
// each opening of the dialog resets the importId so we don't associate it with previous imports anymore
|
|
||||||
importId = '';
|
|
||||||
$importProgressCountWrapper.hide();
|
|
||||||
$importProgressCount.text('0');
|
|
||||||
$fileUploadInput.val('').change(); // to trigger Import button disabling listener below
|
$fileUploadInput.val('').change(); // to trigger Import button disabling listener below
|
||||||
|
|
||||||
$safeImportCheckbox.prop("checked", true);
|
$safeImportCheckbox.prop("checked", true);
|
||||||
@@ -38,9 +28,9 @@ export async function showDialog(node) {
|
|||||||
|
|
||||||
glob.activeDialog = $dialog;
|
glob.activeDialog = $dialog;
|
||||||
|
|
||||||
importIntoNoteId = node.data.noteId;
|
parentNoteId = node.data.noteId;
|
||||||
|
|
||||||
$noteTitle.text(await treeUtils.getNoteTitle(importIntoNoteId));
|
$noteTitle.text(await treeUtils.getNoteTitle(parentNoteId));
|
||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
}
|
}
|
||||||
@@ -49,18 +39,14 @@ $form.submit(() => {
|
|||||||
// disabling so that import is not triggered again.
|
// disabling so that import is not triggered again.
|
||||||
$importButton.attr("disabled", "disabled");
|
$importButton.attr("disabled", "disabled");
|
||||||
|
|
||||||
importIntoNote(importIntoNoteId);
|
importIntoNote(parentNoteId);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
async function importIntoNote(importNoteId) {
|
async function importIntoNote(parentNoteId) {
|
||||||
const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
|
const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
|
||||||
|
|
||||||
// we generate it here (and not on opening) for the case when you try to import multiple times from the same
|
|
||||||
// dialog (which shouldn't happen, but still ...)
|
|
||||||
importId = utils.randomString(10);
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
safeImport: boolToString($safeImportCheckbox),
|
safeImport: boolToString($safeImportCheckbox),
|
||||||
shrinkImages: boolToString($shrinkImagesCheckbox),
|
shrinkImages: boolToString($shrinkImagesCheckbox),
|
||||||
@@ -69,73 +55,15 @@ async function importIntoNote(importNoteId) {
|
|||||||
explodeArchives: boolToString($explodeArchivesCheckbox)
|
explodeArchives: boolToString($explodeArchivesCheckbox)
|
||||||
};
|
};
|
||||||
|
|
||||||
await uploadFiles(importNoteId, files, options);
|
|
||||||
|
|
||||||
$dialog.modal('hide');
|
$dialog.modal('hide');
|
||||||
}
|
|
||||||
|
|
||||||
export async function uploadFiles(importNoteId, files, options) {
|
await importService.uploadFiles(parentNoteId, files, options);
|
||||||
if (files.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let noteId;
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('upload', file);
|
|
||||||
formData.append('importId', importId);
|
|
||||||
|
|
||||||
for (const key in options) {
|
|
||||||
formData.append(key, options[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
({noteId} = await $.ajax({
|
|
||||||
url: baseApiUrl + 'notes/' + importNoteId + '/import',
|
|
||||||
headers: server.getHeaders(),
|
|
||||||
data: formData,
|
|
||||||
dataType: 'json',
|
|
||||||
type: 'POST',
|
|
||||||
timeout: 60 * 60 * 1000,
|
|
||||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
|
||||||
processData: false, // NEEDED, DON'T REMOVE THIS
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
infoService.showMessage("Import finished successfully.");
|
|
||||||
|
|
||||||
await treeService.reloadNote(importNoteId);
|
|
||||||
|
|
||||||
if (noteId) {
|
|
||||||
const node = await treeService.activateNote(noteId);
|
|
||||||
|
|
||||||
node.setExpanded(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function boolToString($el) {
|
function boolToString($el) {
|
||||||
return $el.is(":checked") ? "true" : "false";
|
return $el.is(":checked") ? "true" : "false";
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.subscribeToMessages(async message => {
|
|
||||||
if (message.type === 'import-error') {
|
|
||||||
infoService.showError(message.message);
|
|
||||||
$dialog.modal('hide');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!message.importId || message.importId !== importId) {
|
|
||||||
// incoming messages must correspond to this import instance
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.type === 'import-progress-count') {
|
|
||||||
$importProgressCountWrapper.slideDown();
|
|
||||||
|
|
||||||
$importProgressCount.text(message.progressCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$fileUploadInput.change(() => {
|
$fileUploadInput.change(() => {
|
||||||
if ($fileUploadInput.val()) {
|
if ($fileUploadInput.val()) {
|
||||||
$importButton.removeAttr("disabled");
|
$importButton.removeAttr("disabled");
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export async function showDialog() {
|
|||||||
// set default settings
|
// set default settings
|
||||||
$maxNotesInput.val(20);
|
$maxNotesInput.val(20);
|
||||||
|
|
||||||
const note = noteDetailService.getActiveNote();
|
const note = noteDetailService.getActiveTabNote();
|
||||||
|
|
||||||
if (!note) {
|
if (!note) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import libraryLoader from "../services/library_loader.js";
|
import libraryLoader from "../services/library_loader.js";
|
||||||
import infoService from "../services/info.js";
|
import toastService from "../services/toast.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import noteDetailService from "../services/note_detail.js";
|
import noteDetailService from "../services/note_detail.js";
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ async function convertMarkdownToHtml(text) {
|
|||||||
|
|
||||||
textEditor.model.insertContent(modelFragment, textEditor.model.document.selection);
|
textEditor.model.insertContent(modelFragment, textEditor.model.document.selection);
|
||||||
|
|
||||||
infoService.showMessage("Markdown content has been imported into the document.");
|
toastService.showMessage("Markdown content has been imported into the document.");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importMarkdownInline() {
|
export async function importMarkdownInline() {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function showDialog() {
|
|||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
|
|
||||||
const activeNote = noteDetailService.getActiveNote();
|
const activeNote = noteDetailService.getActiveTabNote();
|
||||||
|
|
||||||
$noteId.text(activeNote.noteId);
|
$noteId.text(activeNote.noteId);
|
||||||
$dateCreated.text(activeNote.dateCreated);
|
$dateCreated.text(activeNote.dateCreated);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ let revisionItems = [];
|
|||||||
let note;
|
let note;
|
||||||
|
|
||||||
export async function showCurrentNoteRevisions() {
|
export async function showCurrentNoteRevisions() {
|
||||||
await showNoteRevisionsDialog(noteDetailService.getActiveNoteId());
|
await showNoteRevisionsDialog(noteDetailService.getActiveTabNoteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
|
export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
|
||||||
@@ -24,7 +24,7 @@ export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
|
|||||||
$list.empty();
|
$list.empty();
|
||||||
$content.empty();
|
$content.empty();
|
||||||
|
|
||||||
note = noteDetailService.getActiveNote();
|
note = noteDetailService.getActiveTabNote();
|
||||||
revisionItems = await server.get('notes/' + noteId + '/revisions');
|
revisionItems = await server.get('notes/' + noteId + '/revisions');
|
||||||
|
|
||||||
for (const item of revisionItems) {
|
for (const item of revisionItems) {
|
||||||
@@ -62,14 +62,4 @@ $list.on('change', () => {
|
|||||||
else {
|
else {
|
||||||
$content.text("Preview isn't available for this note type.");
|
$content.text("Preview isn't available for this note type.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', "a[data-action='note-revision']", event => {
|
|
||||||
const linkEl = $(event.target);
|
|
||||||
const noteId = linkEl.attr('data-note-path');
|
|
||||||
const noteRevisionId = linkEl.attr('data-note-revision-id');
|
|
||||||
|
|
||||||
showNoteRevisionsDialog(noteId, noteRevisionId);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
@@ -11,7 +11,7 @@ export function showDialog() {
|
|||||||
|
|
||||||
$dialog.modal();
|
$dialog.modal();
|
||||||
|
|
||||||
const noteText = noteDetailService.getActiveNote().content;
|
const noteText = noteDetailService.getActiveTabNote().content;
|
||||||
|
|
||||||
$noteSource.text(formatHtml(noteText));
|
$noteSource.text(formatHtml(noteText));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ export async function showDialog() {
|
|||||||
import('./options/appearance.js'),
|
import('./options/appearance.js'),
|
||||||
import('./options/code_notes.js'),
|
import('./options/code_notes.js'),
|
||||||
import('./options/change_password.js'),
|
import('./options/change_password.js'),
|
||||||
import('./options/note_revisions.js'),
|
import('./options/other.js'),
|
||||||
import('./options/protected_session.js'),
|
|
||||||
import('./options/sidebar.js'),
|
import('./options/sidebar.js'),
|
||||||
import('./options/sync.js'),
|
import('./options/sync.js'),
|
||||||
]))
|
]))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import server from "../../services/server.js";
|
import server from "../../services/server.js";
|
||||||
import infoService from "../../services/info.js";
|
import toastService from "../../services/toast.js";
|
||||||
|
|
||||||
export default class AdvancedOptions {
|
export default class AdvancedOptions {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -13,26 +13,26 @@ export default class AdvancedOptions {
|
|||||||
this.$forceFullSyncButton.click(async () => {
|
this.$forceFullSyncButton.click(async () => {
|
||||||
await server.post('sync/force-full-sync');
|
await server.post('sync/force-full-sync');
|
||||||
|
|
||||||
infoService.showMessage("Full sync triggered");
|
toastService.showMessage("Full sync triggered");
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$fillSyncRowsButton.click(async () => {
|
this.$fillSyncRowsButton.click(async () => {
|
||||||
await server.post('sync/fill-sync-rows');
|
await server.post('sync/fill-sync-rows');
|
||||||
|
|
||||||
infoService.showMessage("Sync rows filled successfully");
|
toastService.showMessage("Sync rows filled successfully");
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$anonymizeButton.click(async () => {
|
this.$anonymizeButton.click(async () => {
|
||||||
await server.post('anonymization/anonymize');
|
await server.post('anonymization/anonymize');
|
||||||
|
|
||||||
infoService.showMessage("Created anonymized database");
|
toastService.showMessage("Created anonymized database");
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$cleanupSoftDeletedButton.click(async () => {
|
this.$cleanupSoftDeletedButton.click(async () => {
|
||||||
if (confirm("Do you really want to clean up soft-deleted items?")) {
|
if (confirm("Do you really want to clean up soft-deleted items?")) {
|
||||||
await server.post('cleanup/cleanup-soft-deleted-items');
|
await server.post('cleanup/cleanup-soft-deleted-items');
|
||||||
|
|
||||||
infoService.showMessage("Soft deleted items have been cleaned up");
|
toastService.showMessage("Soft deleted items have been cleaned up");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -40,14 +40,14 @@ export default class AdvancedOptions {
|
|||||||
if (confirm("Do you really want to clean up unused images?")) {
|
if (confirm("Do you really want to clean up unused images?")) {
|
||||||
await server.post('cleanup/cleanup-unused-images');
|
await server.post('cleanup/cleanup-unused-images');
|
||||||
|
|
||||||
infoService.showMessage("Unused images have been cleaned up");
|
toastService.showMessage("Unused images have been cleaned up");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$vacuumDatabaseButton.click(async () => {
|
this.$vacuumDatabaseButton.click(async () => {
|
||||||
await server.post('cleanup/vacuum-database');
|
await server.post('cleanup/vacuum-database');
|
||||||
|
|
||||||
infoService.showMessage("Database has been vacuumed");
|
toastService.showMessage("Database has been vacuumed");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import server from "../../services/server.js";
|
import server from "../../services/server.js";
|
||||||
import protectedSessionHolder from "../../services/protected_session_holder.js";
|
import protectedSessionHolder from "../../services/protected_session_holder.js";
|
||||||
import infoService from "../../services/info.js";
|
import toastService from "../../services/toast.js";
|
||||||
|
|
||||||
export default class ChangePasswordOptions {
|
export default class ChangePasswordOptions {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -39,7 +39,7 @@ export default class ChangePasswordOptions {
|
|||||||
protectedSessionHolder.resetProtectedSession();
|
protectedSessionHolder.resetProtectedSession();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.showError(result.message);
|
toastService.showError(result.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
54
src/public/javascripts/dialogs/options/other.js
Normal file
54
src/public/javascripts/dialogs/options/other.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import optionsService from "../../services/options.js";
|
||||||
|
import server from "../../services/server.js";
|
||||||
|
import toastService from "../../services/toast.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(() => toastService.showMessage("Options change have been saved."));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$spellCheckLanguageCode.change(() => {
|
||||||
|
const opts = { 'spellCheckLanguageCode': this.$spellCheckLanguageCode.val() };
|
||||||
|
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$protectedSessionTimeout.change(() => {
|
||||||
|
const protectedSessionTimeout = this.$protectedSessionTimeout.val();
|
||||||
|
|
||||||
|
server.put('options', { 'protectedSessionTimeout': protectedSessionTimeout }).then(() => {
|
||||||
|
optionsService.reloadOptions();
|
||||||
|
|
||||||
|
toastService.showMessage("Options change have been saved.");
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$noteRevisionsTimeInterval.change(() => {
|
||||||
|
const opts = { 'noteRevisionSnapshotTimeInterval': this.$noteRevisionsTimeInterval.val() };
|
||||||
|
server.put('options', opts).then(() => toastService.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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import server from "../../services/server.js";
|
import server from "../../services/server.js";
|
||||||
import infoService from "../../services/info.js";
|
import toastService from "../../services/toast.js";
|
||||||
|
|
||||||
export default class SyncOptions {
|
export default class SyncOptions {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -15,10 +15,10 @@ export default class SyncOptions {
|
|||||||
const result = await server.post('sync/test');
|
const result = await server.post('sync/test');
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
infoService.showMessage(result.message);
|
toastService.showMessage(result.message);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.showError("Sync server handshake failed, error: " + result.message);
|
toastService.showError("Sync server handshake failed, error: " + result.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ export default class SyncOptions {
|
|||||||
'syncProxy': this.$syncProxy.val()
|
'syncProxy': this.$syncProxy.val()
|
||||||
};
|
};
|
||||||
|
|
||||||
server.put('options', opts).then(() => infoService.showMessage("Options change have been saved."));
|
server.put('options', opts).then(() => toastService.showMessage("Options change have been saved."));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import libraryLoader from '../services/library_loader.js';
|
import libraryLoader from '../services/library_loader.js';
|
||||||
import server from '../services/server.js';
|
import server from '../services/server.js';
|
||||||
import infoService from "../services/info.js";
|
import toastService from "../services/toast.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
|
|
||||||
const $dialog = $("#sql-console-dialog");
|
const $dialog = $("#sql-console-dialog");
|
||||||
@@ -63,11 +63,11 @@ async function execute() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
infoService.showError(result.error);
|
toastService.showError(result.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.showMessage("Query was executed successfully.");
|
toastService.showMessage("Query was executed successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const rows = result.rows;
|
const rows = result.rows;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import treeService from './tree.js';
|
import treeService from './tree.js';
|
||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import treeCache from "./tree_cache.js";
|
import treeCache from "./tree_cache.js";
|
||||||
import treeUtils from "./tree_utils.js";
|
import treeUtils from "./tree_utils.js";
|
||||||
import hoistedNoteService from "./hoisted_note.js";
|
import hoistedNoteService from "./hoisted_note.js";
|
||||||
import noteDetailService from "./note_detail.js";
|
import noteDetailService from "./note_detail.js";
|
||||||
|
import ws from "./ws.js";
|
||||||
|
|
||||||
async function moveBeforeNode(nodesToMove, beforeNode) {
|
async function moveBeforeNode(nodesToMove, beforeNode) {
|
||||||
nodesToMove = await filterRootNote(nodesToMove);
|
nodesToMove = await filterRootNote(nodesToMove);
|
||||||
@@ -105,14 +106,23 @@ async function deleteNodes(nodes) {
|
|||||||
|
|
||||||
const deleteClones = $deleteClonesCheckbox.find("input").is(":checked");
|
const deleteClones = $deleteClonesCheckbox.find("input").is(":checked");
|
||||||
|
|
||||||
|
const taskId = utils.randomString(10);
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
const last = counter === nodes.length;
|
||||||
|
const query = `?taskId=${taskId}&last=${last ? 'true' : 'false'}`;
|
||||||
|
|
||||||
if (deleteClones) {
|
if (deleteClones) {
|
||||||
await server.remove('notes/' + node.data.noteId);
|
await server.remove(`notes/${node.data.noteId}` + query);
|
||||||
|
|
||||||
noteDetailService.noteDeleted(node.data.noteId);
|
noteDetailService.noteDeleted(node.data.noteId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const {noteDeleted} = await server.remove('branches/' + node.data.branchId);
|
const {noteDeleted} = await server.remove(`branches/${node.data.branchId}` + query);
|
||||||
|
|
||||||
if (noteDeleted) {
|
if (noteDeleted) {
|
||||||
noteDetailService.noteDeleted(node.data.noteId);
|
noteDetailService.noteDeleted(node.data.noteId);
|
||||||
@@ -152,9 +162,7 @@ async function deleteNodes(nodes) {
|
|||||||
node.remove();
|
node.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const parentNoteId of parentNoteIds) {
|
await treeService.reloadNotes(parentNoteIds);
|
||||||
await treeService.reloadNote(parentNoteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// activate after all the reloading
|
// activate after all the reloading
|
||||||
if (activeNotePath) {
|
if (activeNotePath) {
|
||||||
@@ -164,8 +172,6 @@ async function deleteNodes(nodes) {
|
|||||||
node.setFocus(true);
|
node.setFocus(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
infoService.showMessage("Note(s) has been deleted.");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +255,33 @@ async function filterRootNote(nodes) {
|
|||||||
&& node.data.noteId !== hoistedNoteId);
|
&& node.data.noteId !== hoistedNoteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeToast(id, message) {
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
title: "Delete status",
|
||||||
|
message: message,
|
||||||
|
icon: "trash"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.subscribeToMessages(async message => {
|
||||||
|
if (message.taskType !== 'delete-notes') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'task-error') {
|
||||||
|
toastService.closePersistent(message.taskId);
|
||||||
|
toastService.showError(message.message);
|
||||||
|
} else if (message.type === 'task-progress-count') {
|
||||||
|
toastService.showPersistent(makeToast(message.taskId, "Delete notes in progress: " + message.progressCount));
|
||||||
|
} else if (message.type === 'task-succeeded') {
|
||||||
|
const toast = makeToast(message.taskId, "Delete finished successfully.");
|
||||||
|
toast.closeAfter = 5000;
|
||||||
|
|
||||||
|
toastService.showPersistent(toast);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
moveBeforeNode,
|
moveBeforeNode,
|
||||||
moveAfterNode,
|
moveAfterNode,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import ScriptContext from "./script_context.js";
|
import ScriptContext from "./script_context.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
|
||||||
async function getAndExecuteBundle(noteId, originEntity = null) {
|
async function getAndExecuteBundle(noteId, originEntity = null) {
|
||||||
const bundle = await server.get('script/bundle/' + noteId);
|
const bundle = await server.get('script/bundle/' + noteId);
|
||||||
@@ -8,8 +8,8 @@ async function getAndExecuteBundle(noteId, originEntity = null) {
|
|||||||
return await executeBundle(bundle, originEntity);
|
return await executeBundle(bundle, originEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeBundle(bundle, originEntity, tabContext) {
|
async function executeBundle(bundle, originEntity, tabContext, $container) {
|
||||||
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext);
|
const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity, tabContext, $container);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await (function () {
|
return await (function () {
|
||||||
@@ -17,7 +17,7 @@ async function executeBundle(bundle, originEntity, tabContext) {
|
|||||||
}.call(apiContext));
|
}.call(apiContext));
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
infoService.showAndLogError(`Execution of ${bundle.noteId} failed with error: ${e.message}`);
|
toastService.showAndLogError(`Execution of ${bundle.noteId} failed with error: ${e.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import treeUtils from "./tree_utils.js";
|
import treeUtils from "./tree_utils.js";
|
||||||
import treeChangesService from "./branches.js";
|
import treeChangesService from "./branches.js";
|
||||||
import cloningService from "./cloning.js";
|
import cloningService from "./cloning.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
|
||||||
let clipboardIds = [];
|
let clipboardIds = [];
|
||||||
let clipboardMode = null;
|
let clipboardMode = null;
|
||||||
@@ -26,7 +26,7 @@ async function pasteAfter(node) {
|
|||||||
// just do nothing
|
// just do nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.throwError("Unrecognized clipboard mode=" + clipboardMode);
|
toastService.throwError("Unrecognized clipboard mode=" + clipboardMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ async function pasteInto(node) {
|
|||||||
// just do nothing
|
// just do nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.throwError("Unrecognized clipboard mode=" + mode);
|
toastService.throwError("Unrecognized clipboard mode=" + mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,14 +62,14 @@ function copy(nodes) {
|
|||||||
clipboardIds = nodes.map(node => node.data.noteId);
|
clipboardIds = nodes.map(node => node.data.noteId);
|
||||||
clipboardMode = 'copy';
|
clipboardMode = 'copy';
|
||||||
|
|
||||||
infoService.showMessage("Note(s) have been copied into clipboard.");
|
toastService.showMessage("Note(s) have been copied into clipboard.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function cut(nodes) {
|
function cut(nodes) {
|
||||||
clipboardIds = nodes.map(node => node.key);
|
clipboardIds = nodes.map(node => node.key);
|
||||||
clipboardMode = 'cut';
|
clipboardMode = 'cut';
|
||||||
|
|
||||||
infoService.showMessage("Note(s) have been cut into clipboard.");
|
toastService.showMessage("Note(s) have been cut into clipboard.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEmpty() {
|
function isEmpty() {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ async function cloneNoteTo(childNoteId, parentNoteId, prefix) {
|
|||||||
|
|
||||||
treeCache.addBranchRelationship(resp.branchId, childNoteId, parentNoteId);
|
treeCache.addBranchRelationship(resp.branchId, childNoteId, parentNoteId);
|
||||||
|
|
||||||
await treeService.reloadNote(parentNoteId);
|
await treeService.reloadNotes([parentNoteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// beware that first arg is noteId and second is branchId!
|
// beware that first arg is noteId and second is branchId!
|
||||||
@@ -30,7 +30,7 @@ async function cloneNoteAfter(noteId, afterBranchId) {
|
|||||||
|
|
||||||
treeCache.addBranchRelationship(resp.branchId, noteId, afterBranch.parentNoteId);
|
treeCache.addBranchRelationship(resp.branchId, noteId, afterBranch.parentNoteId);
|
||||||
|
|
||||||
await treeService.reloadNote(afterBranch.parentNoteId);
|
await treeService.reloadNotes([afterBranch.parentNoteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ const dragAndDropSetup = {
|
|||||||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
|
||||||
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
||||||
|
|
||||||
const importDialog = await import('../dialogs/import.js');
|
const importService = await import('./import.js');
|
||||||
|
|
||||||
importDialog.uploadFiles(node.data.noteId, files, {
|
importService.uploadFiles(node.data.noteId, files, {
|
||||||
safeImport: true,
|
safeImport: true,
|
||||||
shrinkImages: true,
|
shrinkImages: true,
|
||||||
textImportedAsText: true,
|
textImportedAsText: true,
|
||||||
|
|||||||
@@ -172,6 +172,19 @@ function registerEntrypoints() {
|
|||||||
utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor);
|
utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor);
|
||||||
utils.bindGlobalShortcut('ctrl+=', zoomService.increaseZoomFactor);
|
utils.bindGlobalShortcut('ctrl+=', zoomService.increaseZoomFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(document).on('click', "a[data-action='note-revision']", async event => {
|
||||||
|
const linkEl = $(event.target);
|
||||||
|
const noteId = linkEl.attr('data-note-path');
|
||||||
|
const noteRevisionId = linkEl.attr('data-note-revision-id');
|
||||||
|
|
||||||
|
const attributesDialog = await import("../dialogs/note_revisions.js");
|
||||||
|
|
||||||
|
attributesDialog.showNoteRevisionsDialog(noteId, noteRevisionId);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import treeService from './tree.js';
|
import treeService from './tree.js';
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import infoService from './info.js';
|
import toastService from './toast.js';
|
||||||
import linkService from './link.js';
|
import linkService from './link.js';
|
||||||
import treeCache from './tree_cache.js';
|
import treeCache from './tree_cache.js';
|
||||||
import noteDetailService from './note_detail.js';
|
import noteDetailService from './note_detail.js';
|
||||||
@@ -9,6 +9,8 @@ import noteTooltipService from './note_tooltip.js';
|
|||||||
import protectedSessionService from './protected_session.js';
|
import protectedSessionService from './protected_session.js';
|
||||||
import dateNotesService from './date_notes.js';
|
import dateNotesService from './date_notes.js';
|
||||||
import StandardWidget from '../widgets/standard_widget.js';
|
import StandardWidget from '../widgets/standard_widget.js';
|
||||||
|
import ws from "./ws.js";
|
||||||
|
import hoistedNoteService from "./hoisted_note.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
* This is the main frontend API interface for scripts. It's published in the local "api" object.
|
||||||
@@ -16,9 +18,12 @@ import StandardWidget from '../widgets/standard_widget.js';
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @hideconstructor
|
* @hideconstructor
|
||||||
*/
|
*/
|
||||||
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null) {
|
function FrontendScriptApi(startNote, currentNote, originEntity = null, tabContext = null, $container = null) {
|
||||||
const $pluginButtons = $("#plugin-buttons");
|
const $pluginButtons = $("#plugin-buttons");
|
||||||
|
|
||||||
|
/** @property {jQuery} container of all the rendered script content */
|
||||||
|
this.$container = $container;
|
||||||
|
|
||||||
/** @property {object} note where script started executing */
|
/** @property {object} note where script started executing */
|
||||||
this.startNote = startNote;
|
this.startNote = startNote;
|
||||||
/** @property {object} note where script is currently executing */
|
/** @property {object} note where script is currently executing */
|
||||||
@@ -139,9 +144,14 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
currentNoteId: currentNote.noteId,
|
currentNoteId: currentNote.noteId,
|
||||||
originEntityName: "notes", // currently there's no other entity on frontend which can trigger event
|
originEntityName: "notes", // currently there's no other entity on frontend which can trigger event
|
||||||
originEntityId: originEntity ? originEntity.noteId : null
|
originEntityId: originEntity ? originEntity.noteId : null
|
||||||
|
}, {
|
||||||
|
'trilium-source-id': "script"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ret.success) {
|
if (ret.success) {
|
||||||
|
// wait until all the changes done in the script has been synced to frontend before continuing
|
||||||
|
await ws.waitForSyncId(ret.maxSyncId);
|
||||||
|
|
||||||
return ret.executionResult;
|
return ret.executionResult;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -205,7 +215,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @param {string} noteId
|
* @param {string} noteId
|
||||||
* @method
|
* @method
|
||||||
*/
|
*/
|
||||||
this.reloadChildren = async noteId => await treeCache.reloadChildren(noteId);
|
this.reloadNotesAndTheirChildren = async noteId => await treeCache.reloadNotesAndTheirChildren(noteId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} noteId
|
* @param {string} noteId
|
||||||
@@ -241,7 +251,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
this.showMessage = infoService.showMessage;
|
this.showMessage = toastService.showMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show error message to the user.
|
* Show error message to the user.
|
||||||
@@ -249,7 +259,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
this.showError = infoService.showError;
|
this.showError = toastService.showError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh tree
|
* Refresh tree
|
||||||
@@ -272,17 +282,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @method
|
* @method
|
||||||
* @returns {NoteFull} active note (loaded into right pane)
|
* @returns {NoteFull} active note (loaded into right pane)
|
||||||
*/
|
*/
|
||||||
this.getActiveNote = noteDetailService.getActiveNote;
|
this.getActiveTabNote = noteDetailService.getActiveTabNote;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @method
|
* @method
|
||||||
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
||||||
*/
|
*/
|
||||||
this.getActiveNotePath = () => {
|
this.getActiveTabNotePath = noteDetailService.getActiveTabNotePath;
|
||||||
const activeTabContext = noteDetailService.getActiveTabContext();
|
|
||||||
|
|
||||||
return activeTabContext ? activeTabContext.notePath : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method checks whether user navigated away from the note from which the scripts has been started.
|
* This method checks whether user navigated away from the note from which the scripts has been started.
|
||||||
@@ -348,6 +354,15 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
|||||||
* @return {Promise<NoteShort>}
|
* @return {Promise<NoteShort>}
|
||||||
*/
|
*/
|
||||||
this.getYearNote = dateNotesService.getYearNote;
|
this.getYearNote = dateNotesService.getYearNote;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hoist note. See https://github.com/zadam/trilium/wiki/Note-hoisting
|
||||||
|
*
|
||||||
|
* @method
|
||||||
|
* @param {string} noteId - set hoisted note. 'root' will effectively unhoist
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
this.setHoistedNoteId = hoistedNoteService.setHoistedNoteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default FrontendScriptApi;
|
export default FrontendScriptApi;
|
||||||
78
src/public/javascripts/services/import.js
Normal file
78
src/public/javascripts/services/import.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import toastService from "./toast.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 taskId = utils.randomString(10);
|
||||||
|
let noteId;
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
counter++;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('upload', file);
|
||||||
|
formData.append('taskId', taskId);
|
||||||
|
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
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeToast(id, message) {
|
||||||
|
return {
|
||||||
|
id: id,
|
||||||
|
title: "Import status",
|
||||||
|
message: message,
|
||||||
|
icon: "plus"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.subscribeToMessages(async message => {
|
||||||
|
if (message.taskType !== 'import') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.type === 'task-error') {
|
||||||
|
toastService.closePersistent(message.taskId);
|
||||||
|
toastService.showError(message.message);
|
||||||
|
} else if (message.type === 'task-progress-count') {
|
||||||
|
toastService.showPersistent(makeToast(message.taskId, "Import in progress: " + message.progressCount));
|
||||||
|
} else if (message.type === 'task-succeeded') {
|
||||||
|
const toast = makeToast(message.taskId, "Import finished successfully.");
|
||||||
|
toast.closeAfter = 5000;
|
||||||
|
|
||||||
|
toastService.showPersistent(toast);
|
||||||
|
|
||||||
|
await treeService.reloadNotes([message.parentNoteId]);
|
||||||
|
|
||||||
|
if (message.result.importedNoteId) {
|
||||||
|
const node = await treeService.activateNote(message.result.importedNoteId);
|
||||||
|
|
||||||
|
node.setExpanded(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default {
|
||||||
|
uploadFiles
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
import ws from "./ws.js";
|
|
||||||
import utils from "./utils.js";
|
|
||||||
|
|
||||||
function showMessage(message) {
|
|
||||||
console.debug(utils.now(), "message: ", message);
|
|
||||||
|
|
||||||
$.notify({
|
|
||||||
icon: 'jam jam-check',
|
|
||||||
message: message
|
|
||||||
}, getNotifySettings('success', 3000));
|
|
||||||
}
|
|
||||||
|
|
||||||
function showAndLogError(message, delay = 10000) {
|
|
||||||
showError(message, delay);
|
|
||||||
|
|
||||||
ws.logError(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showError(message, delay = 10000) {
|
|
||||||
console.log(utils.now(), "error: ", message);
|
|
||||||
|
|
||||||
$.notify({
|
|
||||||
// options
|
|
||||||
icon: 'jam jam-alert',
|
|
||||||
message: message
|
|
||||||
}, getNotifySettings('danger', delay));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNotifySettings(type, delay) {
|
|
||||||
return {
|
|
||||||
element: 'body',
|
|
||||||
type: type,
|
|
||||||
z_index: 90000,
|
|
||||||
placement: {
|
|
||||||
from: "top",
|
|
||||||
align: "center"
|
|
||||||
},
|
|
||||||
animate: {
|
|
||||||
enter: 'animated fadeInDown',
|
|
||||||
exit: 'animated fadeOutUp'
|
|
||||||
},
|
|
||||||
delay: delay
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function throwError(message) {
|
|
||||||
ws.logError(message);
|
|
||||||
|
|
||||||
throw new Error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
showMessage,
|
|
||||||
showError,
|
|
||||||
showAndLogError,
|
|
||||||
throwError
|
|
||||||
}
|
|
||||||
@@ -14,20 +14,24 @@ function getNotePathFromUrl(url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createNoteLink(notePath, noteTitle = null) {
|
async function createNoteLink(notePath, noteTitle = null, tooltip = true) {
|
||||||
if (!noteTitle) {
|
if (!noteTitle) {
|
||||||
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
||||||
|
|
||||||
noteTitle = await treeUtils.getNoteTitle(noteId);
|
noteTitle = await treeUtils.getNoteTitle(noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteLink = $("<a>", {
|
const $noteLink = $("<a>", {
|
||||||
href: 'javascript:',
|
href: 'javascript:',
|
||||||
text: noteTitle
|
text: noteTitle
|
||||||
}).attr('data-action', 'note')
|
}).attr('data-action', 'note')
|
||||||
.attr('data-note-path', notePath);
|
.attr('data-note-path', notePath);
|
||||||
|
|
||||||
return noteLink;
|
if (!tooltip) {
|
||||||
|
$noteLink.addClass("no-tooltip-preview");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $noteLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createNoteLinkWithPath(notePath, noteTitle = null) {
|
async function createNoteLinkWithPath(notePath, noteTitle = null) {
|
||||||
@@ -113,7 +117,7 @@ function addTextToEditor(text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tabContextMenu(e) {
|
function newTabContextMenu(e) {
|
||||||
const $link = $(e.target);
|
const $link = $(e.target);
|
||||||
|
|
||||||
const notePath = getNotePathFromLink($link);
|
const notePath = getNotePathFromLink($link);
|
||||||
@@ -138,9 +142,9 @@ function tabContextMenu(e) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('contextmenu', '.note-detail-text a', tabContextMenu);
|
$(document).on('contextmenu', '.note-detail-text a', newTabContextMenu);
|
||||||
$(document).on('contextmenu', "a[data-action='note']", tabContextMenu);
|
$(document).on('contextmenu', "a[data-action='note']", newTabContextMenu);
|
||||||
$(document).on('contextmenu', ".note-detail-render a", tabContextMenu);
|
$(document).on('contextmenu', ".note-detail-render a", newTabContextMenu);
|
||||||
|
|
||||||
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
|
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
|
||||||
// of opening the link in new window/tab
|
// of opening the link in new window/tab
|
||||||
@@ -159,6 +163,7 @@ $(document).on('mousedown', '.note-detail-text a', function (e) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(document).on('mousedown', '.note-detail-book a', goToLink);
|
||||||
$(document).on('mousedown', '.note-detail-render a', goToLink);
|
$(document).on('mousedown', '.note-detail-render a', goToLink);
|
||||||
$(document).on('mousedown', '.note-detail-text.ck-read-only a', goToLink);
|
$(document).on('mousedown', '.note-detail-text.ck-read-only a', goToLink);
|
||||||
$(document).on('mousedown', 'span.ck-button__label', e => {
|
$(document).on('mousedown', 'span.ck-button__label', e => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const SELECTED_PATH_KEY = "data-note-path";
|
|||||||
async function autocompleteSource(term, cb) {
|
async function autocompleteSource(term, cb) {
|
||||||
const result = await server.get('autocomplete'
|
const result = await server.get('autocomplete'
|
||||||
+ '?query=' + encodeURIComponent(term)
|
+ '?query=' + encodeURIComponent(term)
|
||||||
+ '&activeNoteId=' + noteDetailService.getActiveNoteId());
|
+ '&activeNoteId=' + noteDetailService.getActiveTabNoteId());
|
||||||
|
|
||||||
if (result.length === 0) {
|
if (result.length === 0) {
|
||||||
result.push({
|
result.push({
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ async function activateOrOpenNote(noteId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {TabContext[]} */
|
||||||
function getTabContexts() {
|
function getTabContexts() {
|
||||||
return tabContexts;
|
return tabContexts;
|
||||||
}
|
}
|
||||||
@@ -107,20 +108,28 @@ function getActiveTabContext() {
|
|||||||
return tabContexts.find(tc => tc.tabId === tabId);
|
return tabContexts.find(tc => tc.tabId === tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @returns {string|null} */
|
||||||
|
function getActiveTabNotePath() {
|
||||||
|
const activeContext = getActiveTabContext();
|
||||||
|
return activeContext ? activeContext.notePath : null;
|
||||||
|
}
|
||||||
|
|
||||||
/** @return {NoteFull} */
|
/** @return {NoteFull} */
|
||||||
function getActiveNote() {
|
function getActiveTabNote() {
|
||||||
const activeContext = getActiveTabContext();
|
const activeContext = getActiveTabContext();
|
||||||
return activeContext ? activeContext.note : null;
|
return activeContext ? activeContext.note : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveNoteId() {
|
/** @return {string|null} */
|
||||||
const activeNote = getActiveNote();
|
function getActiveTabNoteId() {
|
||||||
|
const activeNote = getActiveTabNote();
|
||||||
|
|
||||||
return activeNote ? activeNote.noteId : null;
|
return activeNote ? activeNote.noteId : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActiveNoteType() {
|
/** @return {string|null} */
|
||||||
const activeNote = getActiveNote();
|
function getActiveTabNoteType() {
|
||||||
|
const activeNote = getActiveTabNote();
|
||||||
|
|
||||||
return activeNote ? activeNote.type : null;
|
return activeNote ? activeNote.type : null;
|
||||||
}
|
}
|
||||||
@@ -300,7 +309,7 @@ function addDetailLoadedListener(noteId, callback) {
|
|||||||
|
|
||||||
function fireDetailLoaded() {
|
function fireDetailLoaded() {
|
||||||
for (const {noteId, callback} of detailLoadedListeners) {
|
for (const {noteId, callback} of detailLoadedListeners) {
|
||||||
if (noteId === getActiveNoteId()) {
|
if (noteId === getActiveTabNoteId()) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,7 +346,7 @@ $tabContentsContainer.on("dragover", e => e.preventDefault());
|
|||||||
$tabContentsContainer.on("dragleave", e => e.preventDefault());
|
$tabContentsContainer.on("dragleave", e => e.preventDefault());
|
||||||
|
|
||||||
$tabContentsContainer.on("drop", async e => {
|
$tabContentsContainer.on("drop", async e => {
|
||||||
const activeNote = getActiveNote();
|
const activeNote = getActiveTabNote();
|
||||||
|
|
||||||
if (!activeNote) {
|
if (!activeNote) {
|
||||||
return;
|
return;
|
||||||
@@ -345,9 +354,9 @@ $tabContentsContainer.on("drop", async e => {
|
|||||||
|
|
||||||
const files = [...e.originalEvent.dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
const files = [...e.originalEvent.dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation
|
||||||
|
|
||||||
const importDialog = await import("../dialogs/import.js");
|
const importService = await import("./import.js");
|
||||||
|
|
||||||
importDialog.uploadFiles(activeNote.noteId, files, {
|
importService.uploadFiles(activeNote.noteId, files, {
|
||||||
safeImport: true,
|
safeImport: true,
|
||||||
shrinkImages: true,
|
shrinkImages: true,
|
||||||
textImportedAsText: true,
|
textImportedAsText: true,
|
||||||
@@ -385,6 +394,8 @@ tabRow.addListener('tabRemove', async ({ detail }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$(tabRow.el).on('contextmenu', '.note-tab', e => {
|
$(tabRow.el).on('contextmenu', '.note-tab', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const tab = $(e.target).closest(".note-tab");
|
const tab = $(e.target).closest(".note-tab");
|
||||||
|
|
||||||
contextMenuService.initContextMenu(e, {
|
contextMenuService.initContextMenu(e, {
|
||||||
@@ -495,9 +506,6 @@ export default {
|
|||||||
switchToNote,
|
switchToNote,
|
||||||
loadNote,
|
loadNote,
|
||||||
loadNoteDetail,
|
loadNoteDetail,
|
||||||
getActiveNote,
|
|
||||||
getActiveNoteType,
|
|
||||||
getActiveNoteId,
|
|
||||||
focusOnTitle,
|
focusOnTitle,
|
||||||
focusAndSelectTitle,
|
focusAndSelectTitle,
|
||||||
saveNotesIfChanged,
|
saveNotesIfChanged,
|
||||||
@@ -506,6 +514,10 @@ export default {
|
|||||||
switchToTab,
|
switchToTab,
|
||||||
getTabContexts,
|
getTabContexts,
|
||||||
getActiveTabContext,
|
getActiveTabContext,
|
||||||
|
getActiveTabNotePath,
|
||||||
|
getActiveTabNote,
|
||||||
|
getActiveTabNoteType,
|
||||||
|
getActiveTabNoteId,
|
||||||
getActiveEditor,
|
getActiveEditor,
|
||||||
activateOrOpenNote,
|
activateOrOpenNote,
|
||||||
clearOpenTabsTask,
|
clearOpenTabsTask,
|
||||||
|
|||||||
292
src/public/javascripts/services/note_detail_book.js
Normal file
292
src/public/javascripts/services/note_detail_book.js
Normal 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(), {url: true});
|
||||||
|
}
|
||||||
|
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(' ')
|
||||||
|
.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;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import libraryLoader from "./library_loader.js";
|
import libraryLoader from "./library_loader.js";
|
||||||
import bundleService from "./bundle.js";
|
import bundleService from "./bundle.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import noteDetailService from "./note_detail.js";
|
import noteDetailService from "./note_detail.js";
|
||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
@@ -102,7 +102,7 @@ class NoteDetailCode {
|
|||||||
await server.post('script/run/' + this.ctx.note.noteId);
|
await server.post('script/run/' + this.ctx.note.noteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
infoService.showMessage("Note executed");
|
toastService.showMessage("Note executed");
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoteChange(func) {
|
onNoteChange(func) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class NoteDetailFile {
|
|||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
const open = require("open");
|
const open = require("open");
|
||||||
|
|
||||||
open(this.getFileUrl());
|
open(this.getFileUrl(), {url: true});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
window.location.href = this.getFileUrl();
|
window.location.href = this.getFileUrl();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
class NoteDetailImage {
|
class NoteDetailImage {
|
||||||
@@ -28,10 +28,10 @@ class NoteDetailImage {
|
|||||||
const success = document.execCommand('copy');
|
const success = document.execCommand('copy');
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
infoService.showMessage("Image copied to the clipboard");
|
toastService.showMessage("Image copied to the clipboard");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.showAndLogError("Could not copy the image to clipboard.");
|
toastService.showAndLogError("Could not copy the image to clipboard.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import linkService from "./link.js";
|
|||||||
import libraryLoader from "./library_loader.js";
|
import libraryLoader from "./library_loader.js";
|
||||||
import treeService from "./tree.js";
|
import treeService from "./tree.js";
|
||||||
import contextMenuWidget from "./context_menu.js";
|
import contextMenuWidget from "./context_menu.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import attributeAutocompleteService from "./attribute_autocomplete.js";
|
import attributeAutocompleteService from "./attribute_autocomplete.js";
|
||||||
|
|
||||||
const uniDirectionalOverlays = [
|
const uniDirectionalOverlays = [
|
||||||
@@ -122,7 +122,7 @@ class NoteDetailRelationMap {
|
|||||||
this.clipboard = null;
|
this.clipboard = null;
|
||||||
|
|
||||||
this.$createChildNote.click(async () => {
|
this.$createChildNote.click(async () => {
|
||||||
const promptDialog = await import('"../dialogs/prompt.js"');
|
const promptDialog = await import('../dialogs/prompt.js');
|
||||||
const title = await promptDialog.ask({ message: "Enter title of new note", defaultValue: "new note" });
|
const title = await promptDialog.ask({ message: "Enter title of new note", defaultValue: "new note" });
|
||||||
|
|
||||||
if (!title.trim()) {
|
if (!title.trim()) {
|
||||||
@@ -134,7 +134,7 @@ class NoteDetailRelationMap {
|
|||||||
target: 'into'
|
target: 'into'
|
||||||
});
|
});
|
||||||
|
|
||||||
infoService.showMessage("Click on canvas to place new note");
|
toastService.showMessage("Click on canvas to place new note");
|
||||||
|
|
||||||
// reloading tree so that the new note appears there
|
// reloading tree so that the new note appears there
|
||||||
// no need to wait for it to finish
|
// no need to wait for it to finish
|
||||||
@@ -576,7 +576,7 @@ class NoteDetailRelationMap {
|
|||||||
const exists = this.mapData.notes.some(n => n.noteId === note.noteId);
|
const exists = this.mapData.notes.some(n => n.noteId === note.noteId);
|
||||||
|
|
||||||
if (exists) {
|
if (exists) {
|
||||||
infoService.showError(`Note "${note.title}" is already in the diagram.`);
|
toastService.showError(`Note "${note.title}" is already in the diagram.`);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import bundleService from "./bundle.js";
|
import renderService from "./render.js";
|
||||||
import server from "./server.js";
|
|
||||||
|
|
||||||
class NoteDetailRender {
|
class NoteDetailRender {
|
||||||
/**
|
/**
|
||||||
@@ -16,29 +15,10 @@ class NoteDetailRender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async render() {
|
async render() {
|
||||||
const attributes = await this.ctx.attributes.getAttributes();
|
|
||||||
const renderNotes = attributes.filter(attr =>
|
|
||||||
attr.type === 'relation'
|
|
||||||
&& attr.name === 'renderNote'
|
|
||||||
&& !!attr.value);
|
|
||||||
|
|
||||||
this.$component.show();
|
this.$component.show();
|
||||||
|
this.$noteDetailRenderHelp.hide();
|
||||||
|
|
||||||
this.$noteDetailRenderContent.empty();
|
await renderService.render(this.ctx.note, this.$noteDetailRenderContent, this.ctx);
|
||||||
this.$noteDetailRenderContent.toggle(renderNotes.length > 0);
|
|
||||||
this.$noteDetailRenderHelp.toggle(renderNotes.length === 0);
|
|
||||||
|
|
||||||
for (const renderNote of renderNotes) {
|
|
||||||
const bundle = await server.get('script/bundle/' + renderNote.value);
|
|
||||||
|
|
||||||
this.$noteDetailRenderContent.append(bundle.html);
|
|
||||||
|
|
||||||
const $result = await bundleService.executeBundle(bundle, this.ctx.note, this.ctx);
|
|
||||||
|
|
||||||
if ($result) {
|
|
||||||
this.$noteDetailRenderContent.append($result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getContent() {}
|
getContent() {}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const NOTE_TYPES = [
|
|||||||
{ type: "text", mime: "text/html", title: "Text", selectable: true },
|
{ type: "text", mime: "text/html", title: "Text", selectable: true },
|
||||||
{ type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true },
|
{ type: "relation-map", mime: "application/json", title: "Relation Map", selectable: true },
|
||||||
{ type: "render", mime: '', title: "Render Note", selectable: true },
|
{ type: "render", mime: '', title: "Render Note", selectable: true },
|
||||||
|
{ type: "book", mime: '', title: "Book", selectable: true },
|
||||||
{ type: "code", mime: 'text/plain', title: "Code", selectable: true }
|
{ type: "code", mime: 'text/plain', title: "Code", selectable: true }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,11 @@ function reloadOptions() {
|
|||||||
return optionsReady;
|
return optionsReady;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** just waits for some options without triggering reload */
|
/**
|
||||||
|
* just waits for some options without triggering reload
|
||||||
|
*
|
||||||
|
* @return {Options}
|
||||||
|
*/
|
||||||
async function waitForOptions() {
|
async function waitForOptions() {
|
||||||
return await optionsReady;
|
return await optionsReady;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import noteDetailService from './note_detail.js';
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import protectedSessionHolder from './protected_session_holder.js';
|
import protectedSessionHolder from './protected_session_holder.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
import ws from "./ws.js";
|
||||||
|
|
||||||
const $enterProtectedSessionButton = $("#enter-protected-session-button");
|
const $enterProtectedSessionButton = $("#enter-protected-session-button");
|
||||||
const $leaveProtectedSessionButton = $("#leave-protected-session-button");
|
const $leaveProtectedSessionButton = $("#leave-protected-session-button");
|
||||||
@@ -37,7 +38,7 @@ async function setupProtectedSession(password) {
|
|||||||
const response = await enterProtectedSessionOnServer(password);
|
const response = await enterProtectedSessionOnServer(password);
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
infoService.showError("Wrong password.", 3000);
|
toastService.showError("Wrong password.", 3000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +47,7 @@ async function setupProtectedSession(password) {
|
|||||||
|
|
||||||
await treeService.reload();
|
await treeService.reload();
|
||||||
|
|
||||||
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for children overview)
|
// it's important that tree has been already reloaded at this point since detail also uses tree cache (for book)
|
||||||
// children overview is the reason why we need to reload all tabs
|
|
||||||
await noteDetailService.reloadAllTabs();
|
await noteDetailService.reloadAllTabs();
|
||||||
|
|
||||||
if (protectedSessionDeferred !== null) {
|
if (protectedSessionDeferred !== null) {
|
||||||
@@ -60,7 +60,7 @@ async function setupProtectedSession(password) {
|
|||||||
$enterProtectedSessionButton.hide();
|
$enterProtectedSessionButton.hide();
|
||||||
$leaveProtectedSessionButton.show();
|
$leaveProtectedSessionButton.show();
|
||||||
|
|
||||||
infoService.showMessage("Protected session has been started.");
|
toastService.showMessage("Protected session has been started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enterProtectedSessionOnServer(password) {
|
async function enterProtectedSessionOnServer(password) {
|
||||||
@@ -70,13 +70,13 @@ async function enterProtectedSessionOnServer(password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function protectNoteAndSendToServer() {
|
async function protectNoteAndSendToServer() {
|
||||||
if (!noteDetailService.getActiveNote() || noteDetailService.getActiveNote().isProtected) {
|
if (!noteDetailService.getActiveTabNote() || noteDetailService.getActiveTabNote().isProtected) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await enterProtectedSession();
|
await enterProtectedSession();
|
||||||
|
|
||||||
const note = noteDetailService.getActiveNote();
|
const note = noteDetailService.getActiveTabNote();
|
||||||
note.isProtected = true;
|
note.isProtected = true;
|
||||||
|
|
||||||
await noteDetailService.getActiveTabContext().saveNote();
|
await noteDetailService.getActiveTabContext().saveNote();
|
||||||
@@ -87,10 +87,10 @@ async function protectNoteAndSendToServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function unprotectNoteAndSendToServer() {
|
async function unprotectNoteAndSendToServer() {
|
||||||
const activeNote = noteDetailService.getActiveNote();
|
const activeNote = noteDetailService.getActiveTabNote();
|
||||||
|
|
||||||
if (!activeNote.isProtected) {
|
if (!activeNote.isProtected) {
|
||||||
infoService.showAndLogError(`Note ${activeNote.noteId} is not protected`);
|
toastService.showAndLogError(`Note ${activeNote.noteId} is not protected`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,12 +118,39 @@ async function protectSubtree(noteId, protect) {
|
|||||||
|
|
||||||
await server.put('notes/' + noteId + "/protect/" + (protect ? 1 : 0));
|
await server.put('notes/' + noteId + "/protect/" + (protect ? 1 : 0));
|
||||||
|
|
||||||
infoService.showMessage("Request to un/protect sub tree has finished successfully");
|
|
||||||
|
|
||||||
treeService.reload();
|
treeService.reload();
|
||||||
noteDetailService.reload();
|
noteDetailService.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeToast(message, protectingLabel, text) {
|
||||||
|
return {
|
||||||
|
id: message.taskId,
|
||||||
|
title: protectingLabel + " status",
|
||||||
|
message: text,
|
||||||
|
icon: message.data.protect ? "shield-check" : "shield-close"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.subscribeToMessages(async message => {
|
||||||
|
if (message.taskType !== 'protect-notes') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const protectingLabel = message.data.protect ? "Protecting" : "Unprotecting";
|
||||||
|
|
||||||
|
if (message.type === 'task-error') {
|
||||||
|
toastService.closePersistent(message.taskId);
|
||||||
|
toastService.showError(message.message);
|
||||||
|
} else if (message.type === 'task-progress-count') {
|
||||||
|
toastService.showPersistent(makeToast(message, protectingLabel,protectingLabel + " in progress: " + message.progressCount));
|
||||||
|
} else if (message.type === 'task-succeeded') {
|
||||||
|
const toast = makeToast(message, protectingLabel, protectingLabel + " finished successfully.");
|
||||||
|
toast.closeAfter = 3000;
|
||||||
|
|
||||||
|
toastService.showPersistent(toast);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
protectSubtree,
|
protectSubtree,
|
||||||
enterProtectedSession,
|
enterProtectedSession,
|
||||||
|
|||||||
33
src/public/javascripts/services/render.js
Normal file
33
src/public/javascripts/services/render.js
Normal 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
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import FrontendScriptApi from './frontend_script_api.js';
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import treeCache from './tree_cache.js';
|
import treeCache from './tree_cache.js';
|
||||||
|
|
||||||
async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabContext = null) {
|
async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabContext = null, $container = null) {
|
||||||
const modules = {};
|
const modules = {};
|
||||||
|
|
||||||
const startNote = await treeCache.getNote(startNoteId);
|
const startNote = await treeCache.getNote(startNoteId);
|
||||||
@@ -11,7 +11,7 @@ async function ScriptContext(startNoteId, allNoteIds, originEntity = null, tabCo
|
|||||||
return {
|
return {
|
||||||
modules: modules,
|
modules: modules,
|
||||||
notes: utils.toObject(allNotes, note => [note.noteId, note]),
|
notes: utils.toObject(allNotes, note => [note.noteId, note]),
|
||||||
apis: utils.toObject(allNotes, note => [note.noteId, new FrontendScriptApi(startNote, note, originEntity, tabContext)]),
|
apis: utils.toObject(allNotes, note => [note.noteId, new FrontendScriptApi(startNote, note, originEntity, tabContext, $container)]),
|
||||||
require: moduleNoteIds => {
|
require: moduleNoteIds => {
|
||||||
return moduleName => {
|
return moduleName => {
|
||||||
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import treeService from './tree.js';
|
import treeService from './tree.js';
|
||||||
import treeCache from "./tree_cache.js";
|
import treeCache from "./tree_cache.js";
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
|
||||||
const $searchInput = $("input[name='search-text']");
|
const $searchInput = $("input[name='search-text']");
|
||||||
const $resetSearchButton = $("#reset-search-button");
|
const $resetSearchButton = $("#reset-search-button");
|
||||||
@@ -73,7 +73,7 @@ async function doSearch(searchText) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchText.trim().length === 0) {
|
if (searchText.trim().length === 0) {
|
||||||
infoService.showMessage("Please enter search criteria first.");
|
toastService.showMessage("Please enter search criteria first.");
|
||||||
|
|
||||||
$searchInput.focus();
|
$searchInput.focus();
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ async function doSearch(searchText) {
|
|||||||
const response = await server.get('search/' + encodeURIComponent(searchText));
|
const response = await server.get('search/' + encodeURIComponent(searchText));
|
||||||
|
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
infoService.showError("Search failed.", 3000);
|
toastService.showError("Search failed.", 3000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ async function doSearch(searchText) {
|
|||||||
|
|
||||||
// have at least some feedback which is good especially in situations
|
// have at least some feedback which is good especially in situations
|
||||||
// when the result list does not change with a query
|
// when the result list does not change with a query
|
||||||
infoService.showMessage("Search finished successfully.");
|
toastService.showMessage("Search finished successfully.");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveSearch() {
|
async function saveSearch() {
|
||||||
@@ -139,7 +139,7 @@ async function refreshSearch() {
|
|||||||
activeNode.load(true);
|
activeNode.load(true);
|
||||||
activeNode.setExpanded(true);
|
activeNode.setExpanded(true);
|
||||||
|
|
||||||
infoService.showMessage("Saved search note refreshed.");
|
toastService.showMessage("Saved search note refreshed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|||||||
@@ -1,45 +1,48 @@
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
|
||||||
const REQUEST_LOGGING_ENABLED = false;
|
const REQUEST_LOGGING_ENABLED = false;
|
||||||
|
|
||||||
function getHeaders() {
|
function getHeaders(headers) {
|
||||||
// headers need to be lowercase because node.js automatically converts them to lower case
|
// headers need to be lowercase because node.js automatically converts them to lower case
|
||||||
// so hypothetical protectedSessionId becomes protectedsessionid on the backend
|
// so hypothetical protectedSessionId becomes protectedsessionid on the backend
|
||||||
// also avoiding using underscores instead of dashes since nginx filters them out by default
|
// also avoiding using underscores instead of dashes since nginx filters them out by default
|
||||||
const headers = {
|
const allHeaders = {
|
||||||
'trilium-source-id': glob.sourceId,
|
...{
|
||||||
'x-csrf-token': glob.csrfToken
|
'trilium-source-id': glob.sourceId,
|
||||||
|
'x-csrf-token': glob.csrfToken
|
||||||
|
},
|
||||||
|
...headers
|
||||||
};
|
};
|
||||||
|
|
||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
// passing it explicitely here because of the electron HTTP bypass
|
// passing it explicitely here because of the electron HTTP bypass
|
||||||
headers.cookie = document.cookie;
|
allHeaders.cookie = document.cookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers;
|
return allHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function get(url) {
|
async function get(url, headers = {}) {
|
||||||
return await call('GET', url);
|
return await call('GET', url, null, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function post(url, data) {
|
async function post(url, data, headers = {}) {
|
||||||
return await call('POST', url, data);
|
return await call('POST', url, data, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function put(url, data) {
|
async function put(url, data, headers = {}) {
|
||||||
return await call('PUT', url, data);
|
return await call('PUT', url, data, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove(url) {
|
async function remove(url, headers = {}) {
|
||||||
return await call('DELETE', url);
|
return await call('DELETE', url, null, headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = 1;
|
let i = 1;
|
||||||
const reqResolves = {};
|
const reqResolves = {};
|
||||||
|
|
||||||
async function call(method, url, data) {
|
async function call(method, url, data, headers = {}) {
|
||||||
if (utils.isElectron()) {
|
if (utils.isElectron()) {
|
||||||
const ipc = require('electron').ipcRenderer;
|
const ipc = require('electron').ipcRenderer;
|
||||||
const requestId = i++;
|
const requestId = i++;
|
||||||
@@ -53,7 +56,7 @@ async function call(method, url, data) {
|
|||||||
|
|
||||||
ipc.send('server-request', {
|
ipc.send('server-request', {
|
||||||
requestId: requestId,
|
requestId: requestId,
|
||||||
headers: getHeaders(),
|
headers: getHeaders(headers),
|
||||||
method: method,
|
method: method,
|
||||||
url: "/" + baseApiUrl + url,
|
url: "/" + baseApiUrl + url,
|
||||||
data: data
|
data: data
|
||||||
@@ -84,8 +87,8 @@ async function ajax(url, method, data) {
|
|||||||
|
|
||||||
return await $.ajax(options).catch(e => {
|
return await $.ajax(options).catch(e => {
|
||||||
const message = "Error when calling " + method + " " + url + ": " + e.status + " - " + e.statusText;
|
const message = "Error when calling " + method + " " + url + ": " + e.status + " - " + e.statusText;
|
||||||
infoService.showError(message);
|
toastService.showError(message);
|
||||||
infoService.throwError(message);
|
toastService.throwError(message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
src/public/javascripts/services/spell_check.js
Normal file
48
src/public/javascripts/services/spell_check.js
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
|
||||||
async function syncNow() {
|
async function syncNow() {
|
||||||
const result = await server.post('sync/now');
|
const result = await server.post('sync/now');
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
infoService.showMessage("Sync finished successfully.");
|
toastService.showMessage("Sync finished successfully.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (result.message.length > 50) {
|
if (result.message.length > 50) {
|
||||||
result.message = result.message.substr(0, 50);
|
result.message = result.message.substr(0, 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
infoService.showError("Sync failed: " + result.message);
|
toastService.showError("Sync failed: " + result.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ $("#sync-now-button").click(syncNow);
|
|||||||
async function forceNoteSync(noteId) {
|
async function forceNoteSync(noteId) {
|
||||||
await server.post('sync/force-note-sync/' + noteId);
|
await server.post('sync/force-note-sync/' + noteId);
|
||||||
|
|
||||||
infoService.showMessage("Note added to sync queue.");
|
toastService.showMessage("Note added to sync queue.");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ const componentClasses = {
|
|||||||
'search': "./note_detail_search.js",
|
'search': "./note_detail_search.js",
|
||||||
'render': "./note_detail_render.js",
|
'render': "./note_detail_render.js",
|
||||||
'relation-map': "./note_detail_relation_map.js",
|
'relation-map': "./note_detail_relation_map.js",
|
||||||
'protected-session': "./note_detail_protected_session.js"
|
'protected-session': "./note_detail_protected_session.js",
|
||||||
|
'book': "./note_detail_book.js"
|
||||||
};
|
};
|
||||||
|
|
||||||
let showSidebarInNewTab = true;
|
let showSidebarInNewTab = true;
|
||||||
@@ -64,7 +65,6 @@ class TabContext {
|
|||||||
this.$notePathList = this.$tabContent.find(".note-path-list");
|
this.$notePathList = this.$tabContent.find(".note-path-list");
|
||||||
this.$notePathCount = this.$tabContent.find(".note-path-count");
|
this.$notePathCount = this.$tabContent.find(".note-path-count");
|
||||||
this.$noteDetailComponents = this.$tabContent.find(".note-detail-component");
|
this.$noteDetailComponents = this.$tabContent.find(".note-detail-component");
|
||||||
this.$childrenOverview = this.$tabContent.find(".children-overview");
|
|
||||||
this.$scriptArea = this.$tabContent.find(".note-detail-script-area");
|
this.$scriptArea = this.$tabContent.find(".note-detail-script-area");
|
||||||
this.$savedIndicator = this.$tabContent.find(".saved-indicator");
|
this.$savedIndicator = this.$tabContent.find(".saved-indicator");
|
||||||
this.noteChangeDisabled = false;
|
this.noteChangeDisabled = false;
|
||||||
@@ -115,13 +115,13 @@ class TabContext {
|
|||||||
await this.initComponent();
|
await this.initComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
async initComponent() {
|
async initComponent(disableAutoBook = false) {
|
||||||
const type = this.getComponentType();
|
this.type = this.getComponentType(disableAutoBook);
|
||||||
|
|
||||||
if (!(type in this.components)) {
|
if (!(this.type in this.components)) {
|
||||||
const clazz = await import(componentClasses[type]);
|
const clazz = await import(componentClasses[this.type]);
|
||||||
|
|
||||||
this.components[type] = new clazz.default(this);
|
this.components[this.type] = new clazz.default(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ class TabContext {
|
|||||||
|
|
||||||
this.setTitleBar();
|
this.setTitleBar();
|
||||||
|
|
||||||
this.closeAutocomplete(); // esp. on windows autocomplete is not getting closed automatically
|
this.cleanup(); // esp. on windows autocomplete is not getting closed automatically
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
// we include the note into recent list only if the user stayed on the note at least 5 seconds
|
// we include the note into recent list only if the user stayed on the note at least 5 seconds
|
||||||
@@ -179,8 +179,6 @@ class TabContext {
|
|||||||
|
|
||||||
if (utils.isDesktop()) {
|
if (utils.isDesktop()) {
|
||||||
this.noteType.update();
|
this.noteType.update();
|
||||||
|
|
||||||
this.showChildrenOverview();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.sidebar) {
|
if (this.sidebar) {
|
||||||
@@ -210,11 +208,11 @@ class TabContext {
|
|||||||
this.setTitleBar();
|
this.setTitleBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
async renderComponent() {
|
async renderComponent(disableAutoBook = false) {
|
||||||
await this.initComponent();
|
await this.initComponent(disableAutoBook);
|
||||||
|
|
||||||
for (const componentType in this.components) {
|
for (const componentType in this.components) {
|
||||||
if (componentType !== this.getComponentType()) {
|
if (componentType !== this.type) {
|
||||||
this.components[componentType].cleanup();
|
this.components[componentType].cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,30 +281,31 @@ class TabContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getComponent() {
|
getComponent() {
|
||||||
const type = this.getComponentType();
|
return this.components[this.type];
|
||||||
|
|
||||||
return this.components[type];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getComponentType() {
|
getComponentType(disableAutoBook) {
|
||||||
let type;
|
if (!this.note) {
|
||||||
|
return "empty";
|
||||||
if (this.note) {
|
|
||||||
type = this.note.type;
|
|
||||||
|
|
||||||
if (this.note.isProtected) {
|
|
||||||
if (protectedSessionHolder.isProtectedSessionAvailable()) {
|
|
||||||
protectedSessionHolder.touchProtectedSession();
|
|
||||||
} else {
|
|
||||||
type = 'protected-session';
|
|
||||||
|
|
||||||
// user shouldn't be able to edit note title
|
|
||||||
this.$noteTitle.prop("readonly", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
type = 'empty';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let type = this.note.type;
|
||||||
|
|
||||||
|
if (type === 'text' && !disableAutoBook && utils.isHtmlEmpty(this.note.content) && this.note.hasChildren()) {
|
||||||
|
type = 'book';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.note.isProtected) {
|
||||||
|
if (protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||||
|
protectedSessionHolder.touchProtectedSession();
|
||||||
|
} else {
|
||||||
|
type = 'protected-session';
|
||||||
|
|
||||||
|
// user shouldn't be able to edit note title
|
||||||
|
this.$noteTitle.prop("readonly", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,33 +364,6 @@ class TabContext {
|
|||||||
this.$savedIndicator.fadeOut();
|
this.$savedIndicator.fadeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
async showChildrenOverview() {
|
|
||||||
const attributes = await this.attributes.getAttributes();
|
|
||||||
const hideChildrenOverview = attributes.some(attr => attr.type === 'label' && attr.name === 'hideChildrenOverview')
|
|
||||||
|| this.note.type === 'relation-map'
|
|
||||||
|| this.note.type === 'image'
|
|
||||||
|| this.note.type === 'file';
|
|
||||||
|
|
||||||
if (hideChildrenOverview) {
|
|
||||||
this.$childrenOverview.hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$childrenOverview.empty();
|
|
||||||
|
|
||||||
for (const childBranch of await this.note.getChildBranches()) {
|
|
||||||
const link = $('<a>', {
|
|
||||||
href: 'javascript:',
|
|
||||||
text: await treeUtils.getNoteTitle(childBranch.noteId, childBranch.parentNoteId)
|
|
||||||
}).attr('data-action', 'note').attr('data-note-path', this.notePath + '/' + childBranch.noteId);
|
|
||||||
|
|
||||||
const childEl = $('<div class="child-overview-item">').html(link);
|
|
||||||
this.$childrenOverview.append(childEl);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$childrenOverview.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
async addPath(notePath, isCurrent) {
|
async addPath(notePath, isCurrent) {
|
||||||
const title = await treeUtils.getNotePathTitle(notePath);
|
const title = await treeUtils.getNotePathTitle(notePath);
|
||||||
|
|
||||||
@@ -439,16 +411,20 @@ class TabContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove() {
|
async remove() {
|
||||||
// sometimes there are orphan autocompletes after closing the tab
|
if (this.$tabContent) {
|
||||||
this.closeAutocomplete();
|
// sometimes there are orphan autocompletes after closing the tab
|
||||||
|
this.cleanup();
|
||||||
|
|
||||||
await this.saveNoteIfChanged();
|
await this.saveNoteIfChanged();
|
||||||
this.$tabContent.remove();
|
this.$tabContent.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeAutocomplete() {
|
cleanup() {
|
||||||
if (utils.isDesktop()) {
|
if (this.$tabContent && utils.isDesktop()) {
|
||||||
this.$tabContent.find('.aa-input').autocomplete('close');
|
this.$tabContent.find('.aa-input').autocomplete('close');
|
||||||
|
|
||||||
|
$('.note-tooltip').remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
99
src/public/javascripts/services/toast.js
Normal file
99
src/public/javascripts/services/toast.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import ws from "./ws.js";
|
||||||
|
import utils from "./utils.js";
|
||||||
|
|
||||||
|
function toast(options) {
|
||||||
|
const $toast = $(`<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
|
<div class="toast-header">
|
||||||
|
<strong class="mr-auto"><span class="jam jam-${options.icon}"></span> ${options.title}</strong>
|
||||||
|
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="toast-body">
|
||||||
|
${options.message}
|
||||||
|
</div>
|
||||||
|
</div>`);
|
||||||
|
|
||||||
|
if (options.id) {
|
||||||
|
$toast.attr("id", "toast-" + options.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#toast-container").append($toast);
|
||||||
|
|
||||||
|
$toast.toast({
|
||||||
|
delay: options.delay || 3000,
|
||||||
|
autohide: !!options.autohide
|
||||||
|
});
|
||||||
|
|
||||||
|
$toast.on('hidden.bs.toast', e => e.target.remove());
|
||||||
|
|
||||||
|
$toast.toast("show");
|
||||||
|
|
||||||
|
return $toast;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPersistent(options) {
|
||||||
|
let $toast = $("#toast-" + options.id);
|
||||||
|
|
||||||
|
if ($toast.length > 0) {
|
||||||
|
$toast.find('.toast-body').html(options.message);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options.autohide = false;
|
||||||
|
|
||||||
|
$toast = toast(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.closeAfter) {
|
||||||
|
setTimeout(() => $toast.toast('dispose'), options.closeAfter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closePersistent(id) {
|
||||||
|
$("#toast-persistent-" + id).toast("dispose");
|
||||||
|
}
|
||||||
|
|
||||||
|
function showMessage(message, delay = 2000) {
|
||||||
|
console.debug(utils.now(), "message: ", message);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Info",
|
||||||
|
icon: "check",
|
||||||
|
message: message,
|
||||||
|
autohide: true,
|
||||||
|
delay
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAndLogError(message, delay = 10000) {
|
||||||
|
showError(message, delay);
|
||||||
|
|
||||||
|
ws.logError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showError(message, delay = 10000) {
|
||||||
|
console.log(utils.now(), "error: ", message);
|
||||||
|
|
||||||
|
toast({
|
||||||
|
title: "Error",
|
||||||
|
icon: 'alert',
|
||||||
|
message: message,
|
||||||
|
autohide: true,
|
||||||
|
delay
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwError(message) {
|
||||||
|
ws.logError(message);
|
||||||
|
|
||||||
|
throw new Error(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
showMessage,
|
||||||
|
showError,
|
||||||
|
showAndLogError,
|
||||||
|
throwError,
|
||||||
|
showPersistent,
|
||||||
|
closePersistent
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import treeUtils from './tree_utils.js';
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import server from './server.js';
|
import server from './server.js';
|
||||||
import treeCache from './tree_cache.js';
|
import treeCache from './tree_cache.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import treeBuilder from "./tree_builder.js";
|
import treeBuilder from "./tree_builder.js";
|
||||||
import treeKeyBindings from "./tree_keybindings.js";
|
import treeKeyBindings from "./tree_keybindings.js";
|
||||||
import Branch from '../entities/branch.js';
|
import Branch from '../entities/branch.js';
|
||||||
@@ -25,19 +25,26 @@ const $scrollToActiveNoteButton = $("#scroll-to-active-note-button");
|
|||||||
let setFrontendAsLoaded;
|
let setFrontendAsLoaded;
|
||||||
const frontendLoaded = new Promise(resolve => { setFrontendAsLoaded = resolve; });
|
const frontendLoaded = new Promise(resolve => { setFrontendAsLoaded = resolve; });
|
||||||
|
|
||||||
// focused & not active node can happen during multiselection where the node is selected but not activated
|
/**
|
||||||
// (its content is not displayed in the detail)
|
* focused & not active node can happen during multiselection where the node is selected but not activated
|
||||||
|
* (its content is not displayed in the detail)
|
||||||
|
* @return {FancytreeNode|null}
|
||||||
|
*/
|
||||||
function getFocusedNode() {
|
function getFocusedNode() {
|
||||||
const tree = $tree.fancytree("getTree");
|
const tree = $tree.fancytree("getTree");
|
||||||
|
|
||||||
return tree.getFocusNode();
|
return tree.getFocusNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that if you want to access data like noteId or isProtected, you need to go into "data" property
|
/**
|
||||||
|
* note that if you want to access data like noteId or isProtected, you need to go into "data" property
|
||||||
|
* @return {FancytreeNode|null}
|
||||||
|
*/
|
||||||
function getActiveNode() {
|
function getActiveNode() {
|
||||||
return $tree.fancytree("getActiveNode");
|
return $tree.fancytree("getActiveNode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode[]} */
|
||||||
async function getNodesByBranchId(branchId) {
|
async function getNodesByBranchId(branchId) {
|
||||||
utils.assertArguments(branchId);
|
utils.assertArguments(branchId);
|
||||||
|
|
||||||
@@ -46,6 +53,7 @@ async function getNodesByBranchId(branchId) {
|
|||||||
return getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branchId);
|
return getNodesByNoteId(branch.noteId).filter(node => node.data.branchId === branchId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode[]} */
|
||||||
function getNodesByNoteId(noteId) {
|
function getNodesByNoteId(noteId) {
|
||||||
utils.assertArguments(noteId);
|
utils.assertArguments(noteId);
|
||||||
|
|
||||||
@@ -76,10 +84,12 @@ async function setNodeTitleWithPrefix(node) {
|
|||||||
node.setTitle(utils.escapeHtml(title));
|
node.setTitle(utils.escapeHtml(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode} */
|
||||||
async function expandToNote(notePath, expandOpts) {
|
async function expandToNote(notePath, expandOpts) {
|
||||||
return await getNodeFromPath(notePath, true, expandOpts);
|
return await getNodeFromPath(notePath, true, expandOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode} */
|
||||||
function findChildNode(parentNode, childNoteId) {
|
function findChildNode(parentNode, childNoteId) {
|
||||||
let foundChildNode = null;
|
let foundChildNode = null;
|
||||||
|
|
||||||
@@ -89,16 +99,26 @@ function findChildNode(parentNode, childNoteId) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundChildNode;
|
return foundChildNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode} */
|
||||||
async function getNodeFromPath(notePath, expand = false, expandOpts = {}) {
|
async function getNodeFromPath(notePath, expand = false, expandOpts = {}) {
|
||||||
utils.assertArguments(notePath);
|
utils.assertArguments(notePath);
|
||||||
|
|
||||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||||
|
/** @var {FancytreeNode} */
|
||||||
let parentNode = null;
|
let parentNode = null;
|
||||||
|
|
||||||
for (const childNoteId of await getRunPath(notePath)) {
|
const runPath = await getRunPath(notePath);
|
||||||
|
|
||||||
|
if (!runPath) {
|
||||||
|
console.error("Could not find run path for notePath:", notePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const childNoteId of runPath) {
|
||||||
if (childNoteId === hoistedNoteId) {
|
if (childNoteId === hoistedNoteId) {
|
||||||
// there must be exactly one node with given hoistedNoteId
|
// there must be exactly one node with given hoistedNoteId
|
||||||
parentNode = getNodesByNoteId(childNoteId)[0];
|
parentNode = getNodesByNoteId(childNoteId)[0];
|
||||||
@@ -138,6 +158,7 @@ async function getNodeFromPath(notePath, expand = false, expandOpts = {}) {
|
|||||||
return parentNode;
|
return parentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode} */
|
||||||
async function activateNote(notePath, noteLoadedListener) {
|
async function activateNote(notePath, noteLoadedListener) {
|
||||||
utils.assertArguments(notePath);
|
utils.assertArguments(notePath);
|
||||||
|
|
||||||
@@ -183,6 +204,7 @@ async function activateNote(notePath, noteLoadedListener) {
|
|||||||
/**
|
/**
|
||||||
* Accepts notePath which might or might not be valid and returns an existing path as close to the original
|
* Accepts notePath which might or might not be valid and returns an existing path as close to the original
|
||||||
* notePath as possible.
|
* notePath as possible.
|
||||||
|
* @return {string|null}
|
||||||
*/
|
*/
|
||||||
async function resolveNotePath(notePath) {
|
async function resolveNotePath(notePath) {
|
||||||
const runPath = await getRunPath(notePath);
|
const runPath = await getRunPath(notePath);
|
||||||
@@ -193,6 +215,8 @@ async function resolveNotePath(notePath) {
|
|||||||
/**
|
/**
|
||||||
* Accepts notePath and tries to resolve it. Part of the path might not be valid because of note moving (which causes
|
* Accepts notePath and tries to resolve it. Part of the path might not be valid because of note moving (which causes
|
||||||
* path change) or other corruption, in that case this will try to get some other valid path to the correct note.
|
* path change) or other corruption, in that case this will try to get some other valid path to the correct note.
|
||||||
|
*
|
||||||
|
* @return {string[]}
|
||||||
*/
|
*/
|
||||||
async function getRunPath(notePath) {
|
async function getRunPath(notePath) {
|
||||||
utils.assertArguments(notePath);
|
utils.assertArguments(notePath);
|
||||||
@@ -288,7 +312,7 @@ async function getSomeNotePath(note) {
|
|||||||
const parents = await cur.getParentNotes();
|
const parents = await cur.getParentNotes();
|
||||||
|
|
||||||
if (!parents.length) {
|
if (!parents.length) {
|
||||||
infoService.throwError(`Can't find parents for note ${cur.noteId}`);
|
toastService.throwError(`Can't find parents for note ${cur.noteId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,10 +330,12 @@ async function setExpandedToServer(branchId, isExpanded) {
|
|||||||
await server.put('branches/' + branchId + '/expanded/' + expandedNum);
|
await server.put('branches/' + branchId + '/expanded/' + expandedNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode[]} */
|
||||||
function getSelectedNodes(stopOnParents = false) {
|
function getSelectedNodes(stopOnParents = false) {
|
||||||
return getTree().getSelectedNodes(stopOnParents);
|
return getTree().getSelectedNodes(stopOnParents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {FancytreeNode[]} */
|
||||||
function getSelectedOrActiveNodes(node) {
|
function getSelectedOrActiveNodes(node) {
|
||||||
let notes = getSelectedNodes(true);
|
let notes = getSelectedNodes(true);
|
||||||
|
|
||||||
@@ -499,6 +525,7 @@ function initFancyTree(tree) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return {Fancytree} */
|
||||||
function getTree() {
|
function getTree() {
|
||||||
return $tree.fancytree('getTree');
|
return $tree.fancytree('getTree');
|
||||||
}
|
}
|
||||||
@@ -573,14 +600,11 @@ async function scrollToActiveNote() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBranchBackgroundBasedOnProtectedStatus(noteId) {
|
|
||||||
getNodesByNoteId(noteId).map(node => node.toggleClass("protected", node.data.isProtected));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setProtected(noteId, isProtected) {
|
function setProtected(noteId, isProtected) {
|
||||||
getNodesByNoteId(noteId).map(node => node.data.isProtected = isProtected);
|
getNodesByNoteId(noteId).map(node => {
|
||||||
|
node.data.isProtected = isProtected;
|
||||||
setBranchBackgroundBasedOnProtectedStatus(noteId);
|
node.toggleClass("protected", isProtected);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setNoteTitle(noteId, title) {
|
async function setNoteTitle(noteId, title) {
|
||||||
@@ -612,7 +636,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
|
|||||||
extraOptions.isProtected = false;
|
extraOptions.isProtected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noteDetailService.getActiveNoteType() !== 'text') {
|
if (noteDetailService.getActiveTabNoteType() !== 'text') {
|
||||||
extraOptions.saveSelection = false;
|
extraOptions.saveSelection = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -688,7 +712,7 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
|
|||||||
node.renderTitle();
|
node.renderTitle();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
infoService.throwError("Unrecognized target: " + target);
|
toastService.throwError("Unrecognized target: " + target);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSelectedNodes(); // to unmark previously active node
|
clearSelectedNodes(); // to unmark previously active node
|
||||||
@@ -754,13 +778,20 @@ ws.subscribeToMessages(message => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.subscribeToOutsideSyncMessages(syncData => {
|
// this is a synchronous handler - it returns only once the data has been updated
|
||||||
if (syncData.some(sync => sync.entityName === 'branches')
|
ws.subscribeToOutsideSyncMessages(async syncData => {
|
||||||
|| syncData.some(sync => sync.entityName === 'notes')) {
|
const noteIdsToRefresh = new Set();
|
||||||
|
|
||||||
console.log(utils.now(), "Reloading tree because of background changes");
|
// this has the problem that the former parentNoteId might not be invalidated
|
||||||
|
// and the former location of the branch/note won't be removed.
|
||||||
|
syncData.filter(sync => sync.entityName === 'branches').forEach(sync => noteIdsToRefresh.add(sync.parentNoteId));
|
||||||
|
|
||||||
reload();
|
syncData.filter(sync => sync.entityName === 'notes').forEach(sync => noteIdsToRefresh.add(sync.entityId));
|
||||||
|
|
||||||
|
syncData.filter(sync => sync.entityName === 'note_reordering').forEach(sync => noteIdsToRefresh.add(sync.entityId));
|
||||||
|
|
||||||
|
if (noteIdsToRefresh.size > 0) {
|
||||||
|
await reloadNotes(Array.from(noteIdsToRefresh));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -798,13 +829,31 @@ async function checkFolderStatus(node) {
|
|||||||
node.renderTitle();
|
node.renderTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reloadNote(noteId) {
|
async function reloadNotes(noteIds) {
|
||||||
await treeCache.reloadChildren(noteId);
|
if (noteIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const node of getNodesByNoteId(noteId)) {
|
console.debug("Reloading notes", noteIds);
|
||||||
await node.load(true);
|
|
||||||
|
|
||||||
await checkFolderStatus(node);
|
await treeCache.reloadNotesAndTheirChildren(noteIds);
|
||||||
|
|
||||||
|
const activeNotePath = noteDetailService.getActiveTabNotePath();
|
||||||
|
|
||||||
|
for (const noteId of noteIds) {
|
||||||
|
for (const node of getNodesByNoteId(noteId)) {
|
||||||
|
await node.load(true);
|
||||||
|
|
||||||
|
await checkFolderStatus(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeNotePath) {
|
||||||
|
const node = await getNodeFromPath(activeNotePath);
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
await node.setActive(true, {noEvents: true}); // this node has been already active so no need to fire events again
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -838,6 +887,18 @@ $tree.on('mousedown', '.fancytree-title', e => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function duplicateNote(noteId, parentNoteId) {
|
||||||
|
const {note} = await server.post(`notes/${noteId}/duplicate/${parentNoteId}`);
|
||||||
|
|
||||||
|
await reload();
|
||||||
|
|
||||||
|
await activateNote(note.noteId);
|
||||||
|
|
||||||
|
const origNote = await treeCache.getNote(noteId);
|
||||||
|
toastService.showMessage(`Note "${origNote.title}" has been duplicated`);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
utils.bindGlobalShortcut('alt+c', () => collapseTree()); // don't use shortened form since collapseTree() accepts argument
|
utils.bindGlobalShortcut('alt+c', () => collapseTree()); // don't use shortened form since collapseTree() accepts argument
|
||||||
$collapseTreeButton.click(() => collapseTree());
|
$collapseTreeButton.click(() => collapseTree());
|
||||||
|
|
||||||
@@ -849,7 +910,6 @@ frontendLoaded.then(bundle.executeStartupBundles);
|
|||||||
export default {
|
export default {
|
||||||
reload,
|
reload,
|
||||||
collapseTree,
|
collapseTree,
|
||||||
setBranchBackgroundBasedOnProtectedStatus,
|
|
||||||
setProtected,
|
setProtected,
|
||||||
activateNote,
|
activateNote,
|
||||||
getFocusedNode,
|
getFocusedNode,
|
||||||
@@ -868,12 +928,13 @@ export default {
|
|||||||
setExpandedToServer,
|
setExpandedToServer,
|
||||||
getNodesByNoteId,
|
getNodesByNoteId,
|
||||||
checkFolderStatus,
|
checkFolderStatus,
|
||||||
reloadNote,
|
reloadNotes,
|
||||||
loadTreeCache,
|
loadTreeCache,
|
||||||
expandToNote,
|
expandToNote,
|
||||||
getNodeFromPath,
|
getNodeFromPath,
|
||||||
resolveNotePath,
|
resolveNotePath,
|
||||||
getSomeNotePath,
|
getSomeNotePath,
|
||||||
focusTree,
|
focusTree,
|
||||||
scrollToActiveNote
|
scrollToActiveNote,
|
||||||
|
duplicateNote
|
||||||
};
|
};
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import noteDetailService from "./note_detail.js";
|
|
||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import Branch from "../entities/branch.js";
|
import Branch from "../entities/branch.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
@@ -31,6 +30,16 @@ async function prepareBranch(note) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NOTE_TYPE_ICONS = {
|
||||||
|
"file": "jam jam-attachment",
|
||||||
|
"image": "jam jam-picture",
|
||||||
|
"code": "jam jam-terminal",
|
||||||
|
"render": "jam jam-play",
|
||||||
|
"search": "jam jam-search-folder",
|
||||||
|
"relation-map": "jam jam-map",
|
||||||
|
"book": "jam jam-book"
|
||||||
|
};
|
||||||
|
|
||||||
async function getIcon(note) {
|
async function getIcon(note) {
|
||||||
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
|
||||||
|
|
||||||
@@ -48,23 +57,8 @@ async function getIcon(note) {
|
|||||||
return "jam jam-file";
|
return "jam jam-file";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (note.type === 'file') {
|
else {
|
||||||
return "jam jam-attachment"
|
return NOTE_TYPE_ICONS[note.type];
|
||||||
}
|
|
||||||
else if (note.type === 'image') {
|
|
||||||
return "jam jam-picture"
|
|
||||||
}
|
|
||||||
else if (note.type === 'code') {
|
|
||||||
return "jam jam-terminal"
|
|
||||||
}
|
|
||||||
else if (note.type === 'render') {
|
|
||||||
return "jam jam-play"
|
|
||||||
}
|
|
||||||
else if (note.type === 'search') {
|
|
||||||
return "jam jam-search-folder"
|
|
||||||
}
|
|
||||||
else if (note.type === 'relation-map') {
|
|
||||||
return "jam jam-map"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +155,10 @@ async function getExtraClasses(note) {
|
|||||||
extraClasses.push(utils.getMimeTypeClass(note.mime));
|
extraClasses.push(utils.getMimeTypeClass(note.mime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.archived) {
|
||||||
|
extraClasses.push("archived");
|
||||||
|
}
|
||||||
|
|
||||||
return extraClasses.join(" ");
|
return extraClasses.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import utils from "./utils.js";
|
import utils from "./utils.js";
|
||||||
import Branch from "../entities/branch.js";
|
import Branch from "../entities/branch.js";
|
||||||
import NoteShort from "../entities/note_short.js";
|
import NoteShort from "../entities/note_short.js";
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
import ws from "./ws.js";
|
import ws from "./ws.js";
|
||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
|
|
||||||
@@ -54,24 +54,27 @@ class TreeCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reload children of given noteId.
|
* Reload notes and their children.
|
||||||
*/
|
*/
|
||||||
async reloadChildren(noteId) {
|
async reloadNotesAndTheirChildren(noteIds) {
|
||||||
const resp = await server.post('tree/load', { noteIds: [noteId] });
|
// first load the data before clearing the cache
|
||||||
|
const resp = await server.post('tree/load', { noteIds });
|
||||||
|
|
||||||
for (const childNoteId of this.children[noteId] || []) {
|
for (const noteId of noteIds) {
|
||||||
this.parents[childNoteId] = this.parents[childNoteId].filter(p => p !== noteId);
|
for (const childNoteId of this.children[noteId] || []) {
|
||||||
|
this.parents[childNoteId] = this.parents[childNoteId].filter(p => p !== noteId);
|
||||||
|
|
||||||
const branchId = this.getBranchIdByChildParent(childNoteId, noteId);
|
const branchId = this.getBranchIdByChildParent(childNoteId, noteId);
|
||||||
|
|
||||||
delete this.branches[branchId];
|
delete this.branches[branchId];
|
||||||
delete this.childParentToBranch[childNoteId + '-' + noteId];
|
delete this.childParentToBranch[childNoteId + '-' + noteId];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.children[noteId] = [];
|
||||||
|
|
||||||
|
delete this.notes[noteId];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.children[noteId] = [];
|
|
||||||
|
|
||||||
delete this.notes[noteId];
|
|
||||||
|
|
||||||
this.addResp(resp.notes, resp.branches, resp.relations);
|
this.addResp(resp.notes, resp.branches, resp.relations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,12 +86,10 @@ class TreeCache {
|
|||||||
// to be able to find parents we need first to make sure it is actually loaded
|
// to be able to find parents we need first to make sure it is actually loaded
|
||||||
await this.getNote(noteId);
|
await this.getNote(noteId);
|
||||||
|
|
||||||
for (const parentNoteId of this.parents[noteId] || []) {
|
await this.reloadNotesAndTheirChildren(this.parents[noteId] || []);
|
||||||
await this.reloadChildren(parentNoteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is done to load the new parents for the noteId
|
// this is done to load the new parents for the noteId
|
||||||
await this.reloadChildren(noteId);
|
await this.reloadNotesAndTheirChildren([noteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return {Promise<NoteShort[]>} */
|
/** @return {Promise<NoteShort[]>} */
|
||||||
@@ -197,7 +198,7 @@ class TreeCache {
|
|||||||
const branchId = this.childParentToBranch[key];
|
const branchId = this.childParentToBranch[key];
|
||||||
|
|
||||||
if (!branchId) {
|
if (!branchId) {
|
||||||
infoService.throwError("Cannot find branch for child-parent=" + key);
|
toastService.throwError("Cannot find branch for child-parent=" + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return branchId;
|
return branchId;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import syncService from "./sync.js";
|
|||||||
import hoistedNoteService from './hoisted_note.js';
|
import hoistedNoteService from './hoisted_note.js';
|
||||||
import noteDetailService from './note_detail.js';
|
import noteDetailService from './note_detail.js';
|
||||||
import clipboard from './clipboard.js';
|
import clipboard from './clipboard.js';
|
||||||
|
import protectedSessionHolder from "./protected_session_holder.js";
|
||||||
|
|
||||||
class TreeContextMenu {
|
class TreeContextMenu {
|
||||||
constructor(node) {
|
constructor(node) {
|
||||||
@@ -68,6 +69,8 @@ class TreeContextMenu {
|
|||||||
enabled: !clipboard.isEmpty() && note.type !== 'search' && noSelectedNotes },
|
enabled: !clipboard.isEmpty() && note.type !== 'search' && noSelectedNotes },
|
||||||
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard",
|
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard",
|
||||||
enabled: !clipboard.isEmpty() && isNotRoot && parentNote.type !== 'search' && noSelectedNotes },
|
enabled: !clipboard.isEmpty() && isNotRoot && parentNote.type !== 'search' && noSelectedNotes },
|
||||||
|
{ title: "Duplicate note here", cmd: "duplicateNote", uiIcon: "empty",
|
||||||
|
enabled: noSelectedNotes && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) },
|
||||||
{ title: "----" },
|
{ title: "----" },
|
||||||
{ title: "Export", cmd: "export", uiIcon: "empty",
|
{ title: "Export", cmd: "export", uiIcon: "empty",
|
||||||
enabled: note.type !== 'search' && noSelectedNotes },
|
enabled: note.type !== 'search' && noSelectedNotes },
|
||||||
@@ -152,6 +155,11 @@ class TreeContextMenu {
|
|||||||
else if (cmd === "unhoist") {
|
else if (cmd === "unhoist") {
|
||||||
hoistedNoteService.unhoist();
|
hoistedNoteService.unhoist();
|
||||||
}
|
}
|
||||||
|
else if (cmd === "duplicateNote") {
|
||||||
|
const branch = await treeCache.getBranch(this.node.data.branchId);
|
||||||
|
|
||||||
|
treeService.duplicateNote(this.node.data.noteId, branch.parentNoteId);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
ws.logError("Unknown command: " + cmd);
|
ws.logError("Unknown command: " + cmd);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -201,6 +201,10 @@ function closeActiveDialog() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isHtmlEmpty(html) {
|
||||||
|
return $("<div>").html(html).text().trim().length === 0 && !html.toLowerCase().includes('<img');
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
reloadApp,
|
reloadApp,
|
||||||
parseDate,
|
parseDate,
|
||||||
@@ -231,5 +235,6 @@ export default {
|
|||||||
getCookie,
|
getCookie,
|
||||||
getNoteTypeClass,
|
getNoteTypeClass,
|
||||||
getMimeTypeClass,
|
getMimeTypeClass,
|
||||||
closeActiveDialog
|
closeActiveDialog,
|
||||||
|
isHtmlEmpty
|
||||||
};
|
};
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import utils from './utils.js';
|
import utils from './utils.js';
|
||||||
import infoService from "./info.js";
|
import toastService from "./toast.js";
|
||||||
|
import treeService from "./tree.js";
|
||||||
|
|
||||||
const $outstandingSyncsCount = $("#outstanding-syncs-count");
|
const $outstandingSyncsCount = $("#outstanding-syncs-count");
|
||||||
|
|
||||||
@@ -8,8 +9,9 @@ const outsideSyncMessageHandlers = [];
|
|||||||
const messageHandlers = [];
|
const messageHandlers = [];
|
||||||
|
|
||||||
let ws;
|
let ws;
|
||||||
let lastSyncId;
|
let lastSyncId = window.glob.maxSyncIdAtLoad;
|
||||||
let lastPingTs;
|
let lastPingTs;
|
||||||
|
let syncDataQueue = [];
|
||||||
|
|
||||||
function logError(message) {
|
function logError(message) {
|
||||||
console.log(utils.now(), message); // needs to be separate from .trace()
|
console.log(utils.now(), message); // needs to be separate from .trace()
|
||||||
@@ -35,7 +37,10 @@ function subscribeToAllSyncMessages(messageHandler) {
|
|||||||
allSyncMessageHandlers.push(messageHandler);
|
allSyncMessageHandlers.push(messageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMessage(event) {
|
// used to serialize sync operations
|
||||||
|
let consumeQueuePromise = null;
|
||||||
|
|
||||||
|
async function handleMessage(event) {
|
||||||
const message = JSON.parse(event.data);
|
const message = JSON.parse(event.data);
|
||||||
|
|
||||||
for (const messageHandler of messageHandlers) {
|
for (const messageHandler of messageHandlers) {
|
||||||
@@ -45,32 +50,76 @@ function handleMessage(event) {
|
|||||||
if (message.type === 'sync') {
|
if (message.type === 'sync') {
|
||||||
lastPingTs = Date.now();
|
lastPingTs = Date.now();
|
||||||
|
|
||||||
|
$outstandingSyncsCount.html(message.outstandingSyncs);
|
||||||
|
|
||||||
if (message.data.length > 0) {
|
if (message.data.length > 0) {
|
||||||
console.debug(utils.now(), "Sync data: ", message.data);
|
console.debug(utils.now(), "Sync data: ", message.data);
|
||||||
|
|
||||||
lastSyncId = message.data[message.data.length - 1].id;
|
syncDataQueue.push(...message.data);
|
||||||
|
|
||||||
|
// first wait for all the preceding consumers to finish
|
||||||
|
while (consumeQueuePromise) {
|
||||||
|
await consumeQueuePromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's my turn so start it up
|
||||||
|
consumeQueuePromise = consumeSyncData();
|
||||||
|
|
||||||
|
await consumeQueuePromise;
|
||||||
|
|
||||||
|
// finish and set to null to signal somebody else can pick it up
|
||||||
|
consumeQueuePromise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const syncMessageHandler of allSyncMessageHandlers) {
|
|
||||||
syncMessageHandler(message.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const syncData = message.data.filter(sync => sync.sourceId !== glob.sourceId);
|
|
||||||
|
|
||||||
for (const syncMessageHandler of outsideSyncMessageHandlers) {
|
|
||||||
syncMessageHandler(syncData);
|
|
||||||
}
|
|
||||||
|
|
||||||
$outstandingSyncsCount.html(message.outstandingSyncs);
|
|
||||||
}
|
}
|
||||||
else if (message.type === 'sync-hash-check-failed') {
|
else if (message.type === 'sync-hash-check-failed') {
|
||||||
infoService.showError("Sync check failed!", 60000);
|
toastService.showError("Sync check failed!", 60000);
|
||||||
}
|
}
|
||||||
else if (message.type === 'consistency-checks-failed') {
|
else if (message.type === 'consistency-checks-failed') {
|
||||||
infoService.showError("Consistency checks failed! See logs for details.", 50 * 60000);
|
toastService.showError("Consistency checks failed! See logs for details.", 50 * 60000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let syncIdReachedListeners = [];
|
||||||
|
|
||||||
|
function waitForSyncId(desiredSyncId) {
|
||||||
|
console.log("Waiting for ", desiredSyncId);
|
||||||
|
|
||||||
|
if (desiredSyncId <= lastSyncId) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
syncIdReachedListeners.push({
|
||||||
|
desiredSyncId,
|
||||||
|
resolvePromise: res
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function consumeSyncData() {
|
||||||
|
if (syncDataQueue.length >= 0) {
|
||||||
|
const allSyncData = syncDataQueue;
|
||||||
|
syncDataQueue = [];
|
||||||
|
|
||||||
|
const outsideSyncData = allSyncData.filter(sync => sync.sourceId !== glob.sourceId);
|
||||||
|
|
||||||
|
// the update process should be synchronous as a whole but individual handlers can run in parallel
|
||||||
|
await Promise.all([
|
||||||
|
...allSyncMessageHandlers.map(syncHandler => syncHandler(allSyncData)),
|
||||||
|
...outsideSyncMessageHandlers.map(syncHandler => syncHandler(outsideSyncData))
|
||||||
|
]);
|
||||||
|
|
||||||
|
lastSyncId = allSyncData[allSyncData.length - 1].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncIdReachedListeners
|
||||||
|
.filter(l => l.desiredSyncId <= lastSyncId)
|
||||||
|
.forEach(l => l.resolvePromise());
|
||||||
|
|
||||||
|
syncIdReachedListeners = syncIdReachedListeners
|
||||||
|
.filter(l => l.desiredSyncId > lastSyncId);
|
||||||
|
}
|
||||||
|
|
||||||
function connectWebSocket() {
|
function connectWebSocket() {
|
||||||
const protocol = document.location.protocol === 'https:' ? 'wss' : 'ws';
|
const protocol = document.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||||
|
|
||||||
@@ -112,5 +161,6 @@ export default {
|
|||||||
logError,
|
logError,
|
||||||
subscribeToMessages,
|
subscribeToMessages,
|
||||||
subscribeToAllSyncMessages,
|
subscribeToAllSyncMessages,
|
||||||
subscribeToOutsideSyncMessages
|
subscribeToOutsideSyncMessages,
|
||||||
|
waitForSyncId
|
||||||
};
|
};
|
||||||
@@ -8,21 +8,13 @@ import server from "../services/server.js";
|
|||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="calendar-widget">
|
<div class="calendar-widget">
|
||||||
<div class="calendar-header">
|
<div class="calendar-header">
|
||||||
<button class="calendar-btn" data-calendar-toggle="previous">
|
<button class="calendar-btn jam jam-arrow-left" data-calendar-toggle="previous"></button>
|
||||||
<svg height="24" version="1.1" viewbox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="calendar-header__label" data-calendar-label="month">
|
<div class="calendar-header__label" data-calendar-label="month">
|
||||||
March 2017
|
March 2017
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="calendar-btn" data-calendar-toggle="next">
|
<button class="calendar-btn jam jam-arrow-right" data-calendar-toggle="next"></button>
|
||||||
<svg height="24" version="1.1" viewbox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z"></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="calendar-week">
|
<div class="calendar-week">
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user