mirror of
https://github.com/zadam/trilium.git
synced 2025-10-26 15:56:29 +01:00
Compare commits
281 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
deb67d6275 | ||
|
|
e4039ea5e1 | ||
|
|
78a50be663 | ||
|
|
3d3ad3b99b | ||
|
|
0d9cdcac85 | ||
|
|
350331e2ef | ||
|
|
e8a9e49e9e | ||
|
|
fb55cdaea6 | ||
|
|
b9b2cc8364 | ||
|
|
8dfdd090f5 | ||
|
|
fe7705524a | ||
|
|
2b1b7774f8 | ||
|
|
2d58019d6e | ||
|
|
fe31f08c0d | ||
|
|
ad7a55d305 | ||
|
|
4ce4ac9584 | ||
|
|
88bd65c679 | ||
|
|
9eab3026bb | ||
|
|
7abaedbf31 | ||
|
|
402718d293 | ||
|
|
990a84c202 | ||
|
|
d8e181a828 | ||
|
|
adb8caa8a2 | ||
|
|
7651c53363 | ||
|
|
0f25c8a95f | ||
|
|
1a49894adf | ||
|
|
bd8c078fb9 | ||
|
|
6e060b87b8 | ||
|
|
2375b170ba | ||
|
|
828cce0d78 | ||
|
|
ab535bf147 | ||
|
|
1876664dfb | ||
|
|
1690248e24 | ||
|
|
cbeb8ea17e | ||
|
|
9a13edd490 | ||
|
|
c9113ae752 | ||
|
|
0ec11d29ba | ||
|
|
a6cd25071e | ||
|
|
20fdeee048 | ||
|
|
a79a063d17 | ||
|
|
5e91b1b5e0 | ||
|
|
7877443fb4 | ||
|
|
759e47bfcf | ||
|
|
67bdffb27b | ||
|
|
3386dace3b | ||
|
|
f3a2e2cbde | ||
|
|
3cf3fc13b9 | ||
|
|
2b69abf8ab | ||
|
|
3e49a7dbfa | ||
|
|
4c7c3105e8 | ||
|
|
f782d2bef9 | ||
|
|
ccaa9eae3a | ||
|
|
24c5388e0c | ||
|
|
1cd2711097 | ||
|
|
f0dfe7d552 | ||
|
|
3b8b4da149 | ||
|
|
2150619d62 | ||
|
|
acb76e0630 | ||
|
|
fdb46f9329 | ||
|
|
ca587cccf6 | ||
|
|
571772069a | ||
|
|
79e7762c72 | ||
|
|
d025cfee1b | ||
|
|
7793552443 | ||
|
|
f377a84fa1 | ||
|
|
b8f2797abf | ||
|
|
54d89a9f47 | ||
|
|
1699646b39 | ||
|
|
94a0a31f17 | ||
|
|
10219fb9dd | ||
|
|
50431dd55a | ||
|
|
17b23d92ef | ||
|
|
14f3c783f2 | ||
|
|
c1d0a1e07b | ||
|
|
1d3608b7bf | ||
|
|
d0c655f66a | ||
|
|
ac75fd2ca3 | ||
|
|
3b98428c8c | ||
|
|
7d877d0fef | ||
|
|
cb79f2c7eb | ||
|
|
547a5714ae | ||
|
|
82420fe5f6 | ||
|
|
395913d1bb | ||
|
|
f3a29b55ba | ||
|
|
232321f3a4 | ||
|
|
51dddb0bbb | ||
|
|
8b9bf6e46f | ||
|
|
631a75deec | ||
|
|
3f1d0e5872 | ||
|
|
0fe91d0184 | ||
|
|
2f711a12f8 | ||
|
|
64f32ba38f | ||
|
|
7db4859fb9 | ||
|
|
eee9fcae5c | ||
|
|
9c4a976342 | ||
|
|
e4a09c6207 | ||
|
|
d467db2227 | ||
|
|
b8d6ff0542 | ||
|
|
a9b8e65c9b | ||
|
|
bb8b563ece | ||
|
|
05a8ffb944 | ||
|
|
2502646a64 | ||
|
|
3d95d69f80 | ||
|
|
df751f5d67 | ||
|
|
4f06b6de78 | ||
|
|
d2177cd517 | ||
|
|
0affcf5ad2 | ||
|
|
7a416b107b | ||
|
|
1ff124dab7 | ||
|
|
4cb511bad0 | ||
|
|
73c8d145fa | ||
|
|
ab79f24729 | ||
|
|
cec71f65b3 | ||
|
|
f75c008154 | ||
|
|
474baa7d95 | ||
|
|
a155b6e8d5 | ||
|
|
229974e543 | ||
|
|
6fc19bfb93 | ||
|
|
ccaa108faa | ||
|
|
0a72383495 | ||
|
|
d389100611 | ||
|
|
ea7257a5b2 | ||
|
|
0ebc947fbd | ||
|
|
c89514f9bb | ||
|
|
e0368e395c | ||
|
|
6986c201dd | ||
|
|
bcf163f8a1 | ||
|
|
15aaead7b9 | ||
|
|
d29c5c4758 | ||
|
|
81e2baeee5 | ||
|
|
4cececafc9 | ||
|
|
7c8e7a3f4b | ||
|
|
613d5f93e8 | ||
|
|
4f5b23fbf8 | ||
|
|
a37b9cfc7b | ||
|
|
2bc18bc214 | ||
|
|
f31a998c5d | ||
|
|
5552917533 | ||
|
|
a9702aa6a2 | ||
|
|
d1941cc650 | ||
|
|
f98fa4098f | ||
|
|
5350496ed4 | ||
|
|
b62d79044a | ||
|
|
0db3722ec2 | ||
|
|
d47403c0e7 | ||
|
|
77311954a1 | ||
|
|
b7cf4fe96b | ||
|
|
6d9b702d4c | ||
|
|
6e4c30571c | ||
|
|
5988776b7e | ||
|
|
384da60953 | ||
|
|
21fab412cb | ||
|
|
eb4dfbad92 | ||
|
|
aff9ce97ee | ||
|
|
b0a3f828fb | ||
|
|
76f5736255 | ||
|
|
a82066d899 | ||
|
|
45c5287d53 | ||
|
|
dce54c7af3 | ||
|
|
ee15db0ae1 | ||
|
|
c48dbb0913 | ||
|
|
882ebdbd8f | ||
|
|
6f32d6fabe | ||
|
|
1e123f2390 | ||
|
|
b29155775e | ||
|
|
b821ed28fc | ||
|
|
fdb8959aa1 | ||
|
|
7554cb057b | ||
|
|
fab959539a | ||
|
|
afe44a6fe8 | ||
|
|
7ed526beb7 | ||
|
|
af695802e3 | ||
|
|
156f040880 | ||
|
|
cf6f04defb | ||
|
|
a890b91079 | ||
|
|
e0aabe4f9c | ||
|
|
01cd9d8fb3 | ||
|
|
af10f0f52a | ||
|
|
aa5ede5039 | ||
|
|
21e77c83fc | ||
|
|
b0310e34e2 | ||
|
|
9812b9c272 | ||
|
|
92d5f91aa6 | ||
|
|
b0368c7f17 | ||
|
|
8e1f8c869b | ||
|
|
4688cda493 | ||
|
|
761c51069a | ||
|
|
4dc285d84f | ||
|
|
0e2f8b5734 | ||
|
|
a1402c7c66 | ||
|
|
6ba3e5ab7f | ||
|
|
f740e52ebf | ||
|
|
e9454e4db7 | ||
|
|
749bb90713 | ||
|
|
eb8c296e62 | ||
|
|
dc063983ea | ||
|
|
2595c3ac31 | ||
|
|
9cb8bc5dd8 | ||
|
|
3b690f5456 | ||
|
|
7ef2e7769f | ||
|
|
4c07ac4c4c | ||
|
|
35cd7f3261 | ||
|
|
8c3e2e5eb7 | ||
|
|
d57caee0d3 | ||
|
|
6e83980784 | ||
|
|
295af1f43e | ||
|
|
ed2afe5c20 | ||
|
|
bfc7570e14 | ||
|
|
d9b9d730bb | ||
|
|
ba8a8dca7b | ||
|
|
29eb5a8435 | ||
|
|
5de92171a7 | ||
|
|
29c5e394ab | ||
|
|
07b3d11fe5 | ||
|
|
67663fba50 | ||
|
|
995ebbf577 | ||
|
|
d0e6be3e0c | ||
|
|
01370a5968 | ||
|
|
6c561b5764 | ||
|
|
2953f1bdb8 | ||
|
|
1c057cac75 | ||
|
|
0415efd33b | ||
|
|
e58dc829f5 | ||
|
|
90d10c1ff3 | ||
|
|
5b30291601 | ||
|
|
5193f073e9 | ||
|
|
6c7d8a9667 | ||
|
|
5e9bedd903 | ||
|
|
e712990c03 | ||
|
|
91487b338a | ||
|
|
3ff24d53e5 | ||
|
|
94c904fb40 | ||
|
|
56c7b7f5bd | ||
|
|
19206d1e0d | ||
|
|
420be6d8c6 | ||
|
|
dbd2040bee | ||
|
|
1e979d71c7 | ||
|
|
6bbd4c59bc | ||
|
|
3a54d00e2b | ||
|
|
499c9a7381 | ||
|
|
cd139bdd76 | ||
|
|
60c3b5cccc | ||
|
|
540f9f933a | ||
|
|
a59943094e | ||
|
|
c400a7143c | ||
|
|
1f37d00e42 | ||
|
|
d21e824343 | ||
|
|
ff3f0ee0a0 | ||
|
|
01ff34b5d4 | ||
|
|
0cde7ede24 | ||
|
|
92cb723d0c | ||
|
|
e4bec265c1 | ||
|
|
4da6234911 | ||
|
|
ff0245f05f | ||
|
|
98c81faedb | ||
|
|
465c3b87a7 | ||
|
|
0e5028acd3 | ||
|
|
00c295e4bf | ||
|
|
7084ed4fb1 | ||
|
|
587134c2f8 | ||
|
|
5fac2c7633 | ||
|
|
08a518479b | ||
|
|
bcdfb47939 | ||
|
|
667471e7bb | ||
|
|
3c4ec7fe1a | ||
|
|
4bd7438fca | ||
|
|
0ae9c8da17 | ||
|
|
f921562346 | ||
|
|
643d9077fc | ||
|
|
b4709e8ee5 | ||
|
|
a1181623b7 | ||
|
|
73a6c66379 | ||
|
|
1d5daa8dfd | ||
|
|
c141f4b2c0 | ||
|
|
767aaa18f4 | ||
|
|
8a7228146c | ||
|
|
3d294c5163 | ||
|
|
60231de0ed | ||
|
|
13c0411533 | ||
|
|
de02e9e889 | ||
|
|
e143becb7a |
3
.idea/.gitignore
generated
vendored
3
.idea/.gitignore
generated
vendored
@@ -2,4 +2,5 @@
|
||||
/workspace.xml
|
||||
|
||||
# Datasource local storage ignored files
|
||||
/dataSources.local.xml
|
||||
/dataSources.local.xml
|
||||
/dataSources/
|
||||
|
||||
3
.idea/dataSources.xml
generated
3
.idea/dataSources.xml
generated
@@ -6,9 +6,6 @@
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url>
|
||||
<driver-properties>
|
||||
<property name="enable_load_extension" value="true" />
|
||||
</driver-properties>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dataSource name="document.db">
|
||||
<database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.16">
|
||||
<database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.17">
|
||||
<root id="1">
|
||||
<ServerVersion>3.25.1</ServerVersion>
|
||||
</root>
|
||||
@@ -111,32 +111,34 @@
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="35" parent="7" name="hash">
|
||||
<column id="35" parent="7" name="deleteId">
|
||||
<Position>10</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<DefaultExpression>NULL</DefaultExpression>
|
||||
</column>
|
||||
<column id="36" parent="7" name="hash">
|
||||
<Position>11</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="36" parent="7" name="isInheritable">
|
||||
<Position>11</Position>
|
||||
<column id="37" parent="7" name="isInheritable">
|
||||
<Position>12</Position>
|
||||
<DataType>int|0s</DataType>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<index id="37" parent="7" name="sqlite_autoindex_attributes_1">
|
||||
<index id="38" parent="7" name="sqlite_autoindex_attributes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>attributeId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="38" parent="7" name="IDX_attributes_noteId_index">
|
||||
<index id="39" parent="7" name="IDX_attributes_noteId_index">
|
||||
<ColNames>noteId</ColNames>
|
||||
</index>
|
||||
<index id="39" parent="7" name="IDX_attributes_name_value">
|
||||
<index id="40" parent="7" name="IDX_attributes_name_value">
|
||||
<ColNames>name
|
||||
value</ColNames>
|
||||
</index>
|
||||
<index id="40" parent="7" name="IDX_attributes_name_index">
|
||||
<ColNames>name</ColNames>
|
||||
</index>
|
||||
<index id="41" parent="7" name="IDX_attributes_value_index">
|
||||
<ColNames>value</ColNames>
|
||||
</index>
|
||||
@@ -181,34 +183,36 @@ value</ColNames>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="50" parent="8" name="utcDateModified">
|
||||
<column id="50" parent="8" name="deleteId">
|
||||
<Position>8</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>NULL</DefaultExpression>
|
||||
</column>
|
||||
<column id="51" parent="8" name="utcDateCreated">
|
||||
<column id="51" parent="8" name="utcDateModified">
|
||||
<Position>9</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="52" parent="8" name="hash">
|
||||
<column id="52" parent="8" name="utcDateCreated">
|
||||
<Position>10</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="53" parent="8" name="hash">
|
||||
<Position>11</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<index id="53" parent="8" name="sqlite_autoindex_branches_1">
|
||||
<index id="54" parent="8" name="sqlite_autoindex_branches_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>branchId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="54" parent="8" name="IDX_branches_noteId_parentNoteId">
|
||||
<index id="55" parent="8" name="IDX_branches_noteId_parentNoteId">
|
||||
<ColNames>noteId
|
||||
parentNoteId</ColNames>
|
||||
</index>
|
||||
<index id="55" parent="8" name="IDX_branches_noteId">
|
||||
<ColNames>noteId</ColNames>
|
||||
</index>
|
||||
<index id="56" parent="8" name="IDX_branches_parentNoteId">
|
||||
<ColNames>parentNoteId</ColNames>
|
||||
</index>
|
||||
@@ -423,220 +427,228 @@ parentNoteId</ColNames>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="99" parent="12" name="isErased">
|
||||
<column id="99" parent="12" name="deleteId">
|
||||
<Position>9</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<DefaultExpression>NULL</DefaultExpression>
|
||||
</column>
|
||||
<column id="100" parent="12" name="isErased">
|
||||
<Position>10</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="100" parent="12" name="dateCreated">
|
||||
<Position>10</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="101" parent="12" name="dateModified">
|
||||
<column id="101" parent="12" name="dateCreated">
|
||||
<Position>11</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="102" parent="12" name="utcDateCreated">
|
||||
<column id="102" parent="12" name="dateModified">
|
||||
<Position>12</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="103" parent="12" name="utcDateModified">
|
||||
<column id="103" parent="12" name="utcDateCreated">
|
||||
<Position>13</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="104" parent="12" name="sqlite_autoindex_notes_1">
|
||||
<column id="104" parent="12" name="utcDateModified">
|
||||
<Position>14</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="105" parent="12" name="sqlite_autoindex_notes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="105" parent="12" name="IDX_notes_title">
|
||||
<index id="106" parent="12" name="IDX_notes_title">
|
||||
<ColNames>title</ColNames>
|
||||
</index>
|
||||
<index id="106" parent="12" name="IDX_notes_type">
|
||||
<index id="107" parent="12" name="IDX_notes_type">
|
||||
<ColNames>type</ColNames>
|
||||
</index>
|
||||
<index id="107" parent="12" name="IDX_notes_isDeleted">
|
||||
<index id="108" parent="12" name="IDX_notes_isDeleted">
|
||||
<ColNames>isDeleted</ColNames>
|
||||
</index>
|
||||
<index id="108" parent="12" name="IDX_notes_dateCreated">
|
||||
<index id="109" parent="12" name="IDX_notes_dateCreated">
|
||||
<ColNames>dateCreated</ColNames>
|
||||
</index>
|
||||
<index id="109" parent="12" name="IDX_notes_dateModified">
|
||||
<index id="110" parent="12" name="IDX_notes_dateModified">
|
||||
<ColNames>dateModified</ColNames>
|
||||
</index>
|
||||
<index id="110" parent="12" name="IDX_notes_utcDateCreated">
|
||||
<index id="111" parent="12" name="IDX_notes_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
</index>
|
||||
<index id="111" parent="12" name="IDX_notes_utcDateModified">
|
||||
<index id="112" parent="12" name="IDX_notes_utcDateModified">
|
||||
<ColNames>utcDateModified</ColNames>
|
||||
</index>
|
||||
<key id="112" parent="12">
|
||||
<key id="113" parent="12">
|
||||
<ColNames>noteId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_notes_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="113" parent="13" name="name">
|
||||
<column id="114" parent="13" name="name">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="114" parent="13" name="value">
|
||||
<column id="115" parent="13" name="value">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
</column>
|
||||
<column id="115" parent="13" name="isSynced">
|
||||
<column id="116" parent="13" name="isSynced">
|
||||
<Position>3</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="116" parent="13" name="hash">
|
||||
<column id="117" parent="13" name="hash">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="117" parent="13" name="utcDateCreated">
|
||||
<column id="118" parent="13" name="utcDateCreated">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="118" parent="13" name="utcDateModified">
|
||||
<column id="119" parent="13" name="utcDateModified">
|
||||
<Position>6</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="119" parent="13" name="sqlite_autoindex_options_1">
|
||||
<index id="120" parent="13" name="sqlite_autoindex_options_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>name</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="120" parent="13">
|
||||
<key id="121" parent="13">
|
||||
<ColNames>name</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_options_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="121" parent="14" name="noteId">
|
||||
<column id="122" parent="14" name="noteId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="122" parent="14" name="notePath">
|
||||
<column id="123" parent="14" name="notePath">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="123" parent="14" name="hash">
|
||||
<column id="124" parent="14" name="hash">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="124" parent="14" name="utcDateCreated">
|
||||
<column id="125" parent="14" name="utcDateCreated">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="125" parent="14" name="isDeleted">
|
||||
<column id="126" parent="14" name="isDeleted">
|
||||
<Position>5</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
</column>
|
||||
<index id="126" parent="14" name="sqlite_autoindex_recent_notes_1">
|
||||
<index id="127" parent="14" name="sqlite_autoindex_recent_notes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="127" parent="14">
|
||||
<key id="128" parent="14">
|
||||
<ColNames>noteId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_recent_notes_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="128" parent="15" name="sourceId">
|
||||
<column id="129" parent="15" name="sourceId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="129" parent="15" name="utcDateCreated">
|
||||
<column id="130" parent="15" name="utcDateCreated">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="130" parent="15" name="sqlite_autoindex_source_ids_1">
|
||||
<index id="131" parent="15" name="sqlite_autoindex_source_ids_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>sourceId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="131" parent="15">
|
||||
<index id="132" parent="15" name="IDX_source_ids_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
</index>
|
||||
<key id="133" parent="15">
|
||||
<ColNames>sourceId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="132" parent="16" name="type">
|
||||
<column id="134" parent="16" name="type">
|
||||
<Position>1</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="133" parent="16" name="name">
|
||||
<column id="135" parent="16" name="name">
|
||||
<Position>2</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="134" parent="16" name="tbl_name">
|
||||
<column id="136" parent="16" name="tbl_name">
|
||||
<Position>3</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="135" parent="16" name="rootpage">
|
||||
<column id="137" parent="16" name="rootpage">
|
||||
<Position>4</Position>
|
||||
<DataType>int|0s</DataType>
|
||||
</column>
|
||||
<column id="136" parent="16" name="sql">
|
||||
<column id="138" parent="16" name="sql">
|
||||
<Position>5</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="137" parent="17" name="name">
|
||||
<column id="139" parent="17" name="name">
|
||||
<Position>1</Position>
|
||||
</column>
|
||||
<column id="138" parent="17" name="seq">
|
||||
<column id="140" parent="17" name="seq">
|
||||
<Position>2</Position>
|
||||
</column>
|
||||
<column id="139" parent="18" name="id">
|
||||
<column id="141" parent="18" name="id">
|
||||
<Position>1</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<SequenceIdentity>1</SequenceIdentity>
|
||||
</column>
|
||||
<column id="140" parent="18" name="entityName">
|
||||
<column id="142" parent="18" name="entityName">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="141" parent="18" name="entityId">
|
||||
<column id="143" parent="18" name="entityId">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="142" parent="18" name="sourceId">
|
||||
<column id="144" parent="18" name="sourceId">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="143" parent="18" name="utcSyncDate">
|
||||
<column id="145" parent="18" name="utcSyncDate">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="144" parent="18" name="IDX_sync_entityName_entityId">
|
||||
<index id="146" parent="18" name="IDX_sync_entityName_entityId">
|
||||
<ColNames>entityName
|
||||
entityId</ColNames>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="145" parent="18" name="IDX_sync_utcSyncDate">
|
||||
<index id="147" parent="18" name="IDX_sync_utcSyncDate">
|
||||
<ColNames>utcSyncDate</ColNames>
|
||||
</index>
|
||||
<key id="146" parent="18">
|
||||
<key id="148" parent="18">
|
||||
<ColNames>id</ColNames>
|
||||
<Primary>1</Primary>
|
||||
</key>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:12.13.0-alpine
|
||||
FROM node:12.14.0-alpine
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
PKG_DIR=dist/trilium-linux-x64-server
|
||||
NODE_VERSION=12.13.0
|
||||
NODE_VERSION=12.14.0
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
# Instance name can be used to distinguish between different instances
|
||||
instanceName=
|
||||
|
||||
# Disable automatically generating desktop icon
|
||||
# noDesktopIcon=true
|
||||
|
||||
[Network]
|
||||
# host setting is relevant only for web deployments - set the host on which the server will listen
|
||||
# host=0.0.0.0
|
||||
|
||||
BIN
db/demo.tar
BIN
db/demo.tar
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
UPDATE attributes SET name = 'internalLink' WHERE name = 'internal-link';
|
||||
UPDATE attributes SET name = 'imageLink' WHERE name = 'image-link';
|
||||
UPDATE attributes SET name = 'relationMapLink' WHERE name = 'relation-map-link';
|
||||
5
db/migrations/0155__indexes.sql
Normal file
5
db/migrations/0155__indexes.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
DROP INDEX IF EXISTS IDX_attributes_name_index;
|
||||
DROP INDEX IF EXISTS IDX_branches_noteId;
|
||||
|
||||
CREATE INDEX IDX_source_ids_utcDateCreated
|
||||
on source_ids (utcDateCreated);
|
||||
81
db/migrations/0156__add_deleteId.sql
Normal file
81
db/migrations/0156__add_deleteId.sql
Normal file
@@ -0,0 +1,81 @@
|
||||
CREATE TABLE IF NOT EXISTS "notes_mig" (
|
||||
`noteId` TEXT NOT NULL,
|
||||
`title` TEXT NOT NULL DEFAULT "note",
|
||||
`contentLength` INT NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
`type` TEXT NOT NULL DEFAULT 'text',
|
||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||
`hash` TEXT DEFAULT "" NOT NULL,
|
||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
`isErased` INT NOT NULL DEFAULT 0,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`noteId`));
|
||||
|
||||
INSERT INTO notes_mig (noteId, title, contentLength, isProtected, type, mime, hash, isDeleted, isErased, dateCreated, dateModified, utcDateCreated, utcDateModified)
|
||||
SELECT noteId, title, -1, isProtected, type, mime, hash, isDeleted, isErased, dateCreated, dateModified, utcDateCreated, utcDateModified FROM notes;
|
||||
|
||||
DROP TABLE notes;
|
||||
ALTER TABLE notes_mig RENAME TO notes;
|
||||
|
||||
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`);
|
||||
CREATE INDEX `IDX_notes_title` ON `notes` (`title`);
|
||||
CREATE INDEX `IDX_notes_type` ON `notes` (`type`);
|
||||
CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
|
||||
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "branches_mig" (
|
||||
`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,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
utcDateCreated TEXT NOT NULL,
|
||||
hash TEXT DEFAULT "" NOT NULL,
|
||||
PRIMARY KEY(`branchId`));
|
||||
|
||||
INSERT INTO branches_mig (branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, utcDateModified, utcDateCreated, hash)
|
||||
SELECT branchId, noteId, parentNoteId, notePosition, prefix, isExpanded, isDeleted, utcDateModified, utcDateCreated, hash FROM branches;
|
||||
|
||||
DROP TABLE branches;
|
||||
ALTER TABLE branches_mig RENAME TO branches;
|
||||
|
||||
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
||||
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "attributes_mig"
|
||||
(
|
||||
attributeId TEXT not null primary key,
|
||||
noteId TEXT not null,
|
||||
type TEXT not null,
|
||||
name TEXT not null,
|
||||
value TEXT default '' not null,
|
||||
position INT default 0 not null,
|
||||
utcDateCreated TEXT not null,
|
||||
utcDateModified TEXT not null,
|
||||
isDeleted INT not null,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
hash TEXT default "" not null,
|
||||
isInheritable int DEFAULT 0 NULL);
|
||||
|
||||
INSERT INTO attributes_mig (attributeId, noteId, type, name, value, position, utcDateCreated, utcDateModified, isDeleted, hash, isInheritable)
|
||||
SELECT attributeId, noteId, type, name, value, position, utcDateCreated, utcDateModified, isDeleted, hash, isInheritable FROM attributes;
|
||||
|
||||
DROP TABLE attributes;
|
||||
ALTER TABLE attributes_mig RENAME TO attributes;
|
||||
|
||||
CREATE INDEX IDX_attributes_name_value
|
||||
on attributes (name, value);
|
||||
CREATE INDEX IDX_attributes_noteId_index
|
||||
on attributes (noteId);
|
||||
CREATE INDEX IDX_attributes_value_index
|
||||
on attributes (value);
|
||||
1
db/migrations/0157__fix_contentLength.sql
Normal file
1
db/migrations/0157__fix_contentLength.sql
Normal file
@@ -0,0 +1 @@
|
||||
UPDATE notes SET contentLength = COALESCE((SELECT COALESCE(LENGTH(content), 0) FROM note_contents WHERE note_contents.noteId = notes.noteId), -1);
|
||||
118
db/schema.sql
118
db/schema.sql
@@ -9,6 +9,8 @@ CREATE TABLE IF NOT EXISTS "source_ids" (
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
PRIMARY KEY(`sourceId`)
|
||||
);
|
||||
CREATE INDEX IDX_source_ids_utcDateCreated
|
||||
on source_ids (utcDateCreated);
|
||||
CREATE TABLE IF NOT EXISTS "api_tokens"
|
||||
(
|
||||
apiTokenId TEXT PRIMARY KEY NOT NULL,
|
||||
@@ -25,19 +27,6 @@ CREATE TABLE IF NOT EXISTS "options"
|
||||
utcDateCreated TEXT not null,
|
||||
utcDateModified TEXT NOT NULL
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "attributes"
|
||||
(
|
||||
attributeId TEXT not null primary key,
|
||||
noteId TEXT not null,
|
||||
type TEXT not null,
|
||||
name TEXT not null,
|
||||
value TEXT default '' not null,
|
||||
position INT default 0 not null,
|
||||
utcDateCreated TEXT not null,
|
||||
utcDateModified TEXT not null,
|
||||
isDeleted INT not null,
|
||||
hash TEXT default "" not null,
|
||||
isInheritable int DEFAULT 0 NULL);
|
||||
CREATE UNIQUE INDEX `IDX_sync_entityName_entityId` ON `sync` (
|
||||
`entityName`,
|
||||
`entityId`
|
||||
@@ -45,14 +34,6 @@ CREATE UNIQUE INDEX `IDX_sync_entityName_entityId` ON `sync` (
|
||||
CREATE INDEX `IDX_sync_utcSyncDate` ON `sync` (
|
||||
`utcSyncDate`
|
||||
);
|
||||
CREATE INDEX IDX_attributes_name_value
|
||||
on attributes (name, value);
|
||||
CREATE INDEX IDX_attributes_name_index
|
||||
on attributes (name);
|
||||
CREATE INDEX IDX_attributes_noteId_index
|
||||
on attributes (noteId);
|
||||
CREATE INDEX IDX_attributes_value_index
|
||||
on attributes (value);
|
||||
CREATE TABLE IF NOT EXISTS "note_contents" (
|
||||
`noteId` TEXT NOT NULL,
|
||||
`content` TEXT NULL DEFAULT NULL,
|
||||
@@ -68,47 +49,10 @@ CREATE TABLE recent_notes
|
||||
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);
|
||||
CREATE TABLE IF NOT EXISTS "note_revision_contents" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
`content` TEXT,
|
||||
hash TEXT DEFAULT '' NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL);
|
||||
CREATE TABLE IF NOT EXISTS "notes" (
|
||||
`noteId` TEXT NOT NULL,
|
||||
`title` TEXT NOT NULL DEFAULT "note",
|
||||
`contentLength` INT NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
`type` TEXT NOT NULL DEFAULT 'text',
|
||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||
`hash` TEXT DEFAULT "" NOT NULL,
|
||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||
`isErased` INT NOT NULL DEFAULT 0,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`noteId`));
|
||||
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`);
|
||||
CREATE INDEX `IDX_notes_title` ON `notes` (`title`);
|
||||
CREATE INDEX `IDX_notes_type` ON `notes` (`type`);
|
||||
CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
|
||||
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
||||
CREATE TABLE IF NOT EXISTS "note_revisions" (`noteRevisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
`noteId` TEXT NOT NULL,
|
||||
`title` TEXT,
|
||||
@@ -128,3 +72,61 @@ CREATE INDEX `IDX_note_revisions_utcDateCreated` ON `note_revisions` (`utcDateCr
|
||||
CREATE INDEX `IDX_note_revisions_utcDateLastEdited` ON `note_revisions` (`utcDateLastEdited`);
|
||||
CREATE INDEX `IDX_note_revisions_dateCreated` ON `note_revisions` (`dateCreated`);
|
||||
CREATE INDEX `IDX_note_revisions_dateLastEdited` ON `note_revisions` (`dateLastEdited`);
|
||||
CREATE TABLE IF NOT EXISTS "notes" (
|
||||
`noteId` TEXT NOT NULL,
|
||||
`title` TEXT NOT NULL DEFAULT "note",
|
||||
`contentLength` INT NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
`type` TEXT NOT NULL DEFAULT 'text',
|
||||
`mime` TEXT NOT NULL DEFAULT 'text/html',
|
||||
`hash` TEXT DEFAULT "" NOT NULL,
|
||||
`isDeleted` INT NOT NULL DEFAULT 0,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
`isErased` INT NOT NULL DEFAULT 0,
|
||||
`dateCreated` TEXT NOT NULL,
|
||||
`dateModified` TEXT NOT NULL,
|
||||
`utcDateCreated` TEXT NOT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
PRIMARY KEY(`noteId`));
|
||||
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`);
|
||||
CREATE INDEX `IDX_notes_title` ON `notes` (`title`);
|
||||
CREATE INDEX `IDX_notes_type` ON `notes` (`type`);
|
||||
CREATE INDEX `IDX_notes_dateCreated` ON `notes` (`dateCreated`);
|
||||
CREATE INDEX `IDX_notes_dateModified` ON `notes` (`dateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateModified` ON `notes` (`utcDateModified`);
|
||||
CREATE INDEX `IDX_notes_utcDateCreated` ON `notes` (`utcDateCreated`);
|
||||
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,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
`utcDateModified` TEXT NOT NULL,
|
||||
utcDateCreated TEXT NOT NULL,
|
||||
hash TEXT DEFAULT "" NOT NULL,
|
||||
PRIMARY KEY(`branchId`));
|
||||
CREATE INDEX `IDX_branches_noteId_parentNoteId` ON `branches` (`noteId`,`parentNoteId`);
|
||||
CREATE INDEX IDX_branches_parentNoteId ON branches (parentNoteId);
|
||||
CREATE TABLE IF NOT EXISTS "attributes"
|
||||
(
|
||||
attributeId TEXT not null primary key,
|
||||
noteId TEXT not null,
|
||||
type TEXT not null,
|
||||
name TEXT not null,
|
||||
value TEXT default '' not null,
|
||||
position INT default 0 not null,
|
||||
utcDateCreated TEXT not null,
|
||||
utcDateModified TEXT not null,
|
||||
isDeleted INT not null,
|
||||
`deleteId` TEXT DEFAULT NULL,
|
||||
hash TEXT default "" not null,
|
||||
isInheritable int DEFAULT 0 NULL);
|
||||
CREATE INDEX IDX_attributes_name_value
|
||||
on attributes (name, value);
|
||||
CREATE INDEX IDX_attributes_noteId_index
|
||||
on attributes (noteId);
|
||||
CREATE INDEX IDX_attributes_value_index
|
||||
on attributes (value);
|
||||
|
||||
@@ -396,7 +396,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line313">line 313</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line394">line 394</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -534,6 +534,375 @@ the backend.
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="createDataNote"><span class="type-signature"></span>createDataNote<span class="signature">(parentNoteId, title, content)</span><span class="type-signature"> → {Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}>}</span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Create data note - data in this context means object serializable to JSON. Created note will be of type 'code' and
|
||||
JSON MIME type. See also createNewNote() for more options.
|
||||
</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>parentNoteId</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>title</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>content</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line204">line 204</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}></span>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="createNewNote"><span class="type-signature"></span>createNewNote<span class="signature">(params<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}>}</span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
<th>Attributes</th>
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>params</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="global.html#CreateNewNoteParams">CreateNewNoteParams</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line231">line 231</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
<div class="param-desc">
|
||||
object contains newly created entities note and branch
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}></span>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="createNote"><span class="type-signature"></span>createNote<span class="signature">(parentNoteId, title, content<span class="signature-attributes">opt</span>, extraOptions<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}>}</span></h4>
|
||||
|
||||
|
||||
@@ -760,7 +1129,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line198">line 198</a>
|
||||
<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>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -818,7 +1187,7 @@ the backend.
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="createNoteAndRefresh"><span class="type-signature"></span>createNoteAndRefresh<span class="signature">(parentNoteId, title, content<span class="signature-attributes">opt</span>, extraOptions<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}>}</span></h4>
|
||||
<h4 class="name" id="createTextNote"><span class="type-signature"></span>createTextNote<span class="signature">(parentNoteId, title, content)</span><span class="type-signature"> → {Promise.<{note: <a href="Note.html">Note</a>, branch: <a href="Branch.html">Branch</a>}>}</span></h4>
|
||||
|
||||
|
||||
|
||||
@@ -826,7 +1195,7 @@ the backend.
|
||||
|
||||
|
||||
<div class="description">
|
||||
Creates new note according to given params and force all connected clients to refresh their tree.
|
||||
Create text note. See also createNewNote() for more options.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -850,12 +1219,8 @@ the backend.
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
<th>Attributes</th>
|
||||
|
||||
|
||||
|
||||
<th>Default</th>
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
@@ -879,22 +1244,10 @@ the backend.
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last">create new note under this parent</td>
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -914,19 +1267,7 @@ the backend.
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
@@ -949,62 +1290,7 @@ the backend.
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
""
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>extraOptions</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="global.html#CreateNoteExtraOptions">CreateNoteExtraOptions</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
<td class="default">
|
||||
|
||||
{}
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
@@ -1048,7 +1334,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line211">line 211</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line188">line 188</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1076,10 +1362,6 @@ the backend.
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
<div class="param-desc">
|
||||
object contains newly created entities note and branch
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
@@ -1533,7 +1815,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line318">line 318</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line399">line 399</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1997,7 +2279,7 @@ the backend.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line241">line 241</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line314">line 314</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2765,7 +3047,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line260">line 260</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line341">line 341</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3418,7 +3700,113 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line232">line 232</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line305">line 305</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">Promise.<(<a href="Note.html">Note</a>|null)></span>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="getTodayNote"><span class="type-signature"></span>getTodayNote<span class="signature">()</span><span class="type-signature"> → {Promise.<(<a href="Note.html">Note</a>|null)>}</span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Returns today's day note. If such note doesn't exist, it is created.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line322">line 322</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3596,7 +3984,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line251">line 251</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line332">line 332</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3751,7 +4139,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line269">line 269</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line350">line 350</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3901,7 +4289,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line224">line 224</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line297">line 297</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4404,7 +4792,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line290">line 290</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line371">line 371</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4537,7 +4925,7 @@ This method looks similar to toggleNoteInParent() but differs because we're look
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line276">line 276</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line357">line 357</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4912,7 +5300,7 @@ transactional by default.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line303">line 303</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line384">line 384</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -107,6 +107,10 @@ class Attribute extends Entity {
|
||||
|
||||
async beforeSaving() {
|
||||
if (!this.value) {
|
||||
if (this.type === 'relation') {
|
||||
throw new Error(`Cannot save relation ${this.name} since it does not target any note.`);
|
||||
}
|
||||
|
||||
// null value isn't allowed
|
||||
this.value = "";
|
||||
}
|
||||
@@ -137,6 +141,7 @@ class Attribute extends Entity {
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.isOwned;
|
||||
delete pojo.__note;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,10 @@ class Note extends Entity {
|
||||
|
||||
/** @returns {Promise} */
|
||||
async setContent(content) {
|
||||
if (content === null || content === undefined) {
|
||||
throw new Error(`Cannot set null content to note ${this.noteId}`);
|
||||
}
|
||||
|
||||
// force updating note itself so that dateModified is represented correctly even for the content
|
||||
this.forcedChange = true;
|
||||
this.contentLength = content.length;
|
||||
@@ -220,26 +224,36 @@ class Note extends Entity {
|
||||
return null;
|
||||
}
|
||||
|
||||
async loadOwnedAttributesToCache() {
|
||||
this.__ownedAttributeCache = await repository.getEntities(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`, [this.noteId]);
|
||||
return this.__ownedAttributeCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Attribute[]>} attributes belonging to this specific note (excludes inherited attributes)
|
||||
* This method is a faster variant of getAttributes() which looks for only owned attributes.
|
||||
* Use when inheritance is not needed and/or in batch/performance sensitive operations.
|
||||
*
|
||||
* This method can be significantly faster than the getAttributes()
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} note's "owned" attributes - excluding inherited ones
|
||||
*/
|
||||
async getOwnedAttributes(type, name) {
|
||||
let query = `SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`;
|
||||
const params = [this.noteId];
|
||||
|
||||
if (type) {
|
||||
query += ` AND type = ?`;
|
||||
params.push(type);
|
||||
if (!this.__ownedAttributeCache) {
|
||||
await this.loadOwnedAttributesToCache();
|
||||
}
|
||||
|
||||
if (name) {
|
||||
query += ` AND name = ?`;
|
||||
params.push(name);
|
||||
if (type && name) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.__ownedAttributeCache.slice();
|
||||
}
|
||||
|
||||
return await repository.getEntities(query, params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -261,19 +275,26 @@ class Note extends Entity {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
async getAttributes(type, name) {
|
||||
if (!this.__attributeCache) {
|
||||
await this.loadAttributesToCache();
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (type && name) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.__attributeCache;
|
||||
return this.__attributeCache.slice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,7 +303,15 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
return await this.getAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), excluding inherited ones
|
||||
*/
|
||||
async getOwnedLabels(name) {
|
||||
return await this.getOwnedAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -290,7 +319,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
return await this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,7 +327,15 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
return await this.getAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), excluding inherited ones
|
||||
*/
|
||||
async getOwnedRelations(name) {
|
||||
return await this.getOwnedAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +358,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
return await this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,6 +367,7 @@ class Note extends Entity {
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.__attributeCache = null;
|
||||
this.__ownedAttributeCache = null;
|
||||
}
|
||||
|
||||
/** @returns {Promise<void>} */
|
||||
@@ -339,11 +377,10 @@ class Note extends Entity {
|
||||
tree(noteId, level) AS (
|
||||
SELECT ?, 0
|
||||
UNION
|
||||
SELECT branches.parentNoteId, tree.level + 1 FROM branches
|
||||
SELECT branches.parentNoteId, tree.level + 1
|
||||
FROM branches
|
||||
JOIN tree ON branches.noteId = tree.noteId
|
||||
JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
WHERE notes.isDeleted = 0
|
||||
AND branches.isDeleted = 0
|
||||
WHERE branches.isDeleted = 0
|
||||
),
|
||||
treeWithAttrs(noteId, level) AS (
|
||||
SELECT * FROM tree
|
||||
@@ -362,6 +399,11 @@ class Note extends Entity {
|
||||
// we order by noteId so that attributes from same note stay together. Actual noteId ordering doesn't matter.
|
||||
|
||||
const filteredAttributes = attributes.filter((attr, index) => {
|
||||
// if this exact attribute already appears then don't include it (can happen via cloning)
|
||||
if (attributes.findIndex(it => it.attributeId === attr.attributeId) !== index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr.isDefinition()) {
|
||||
const firstDefinitionIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name);
|
||||
|
||||
@@ -405,6 +447,15 @@ class Note extends Entity {
|
||||
return !!await this.getAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<boolean>} true if note has an attribute with given type and name (excluding inherited)
|
||||
*/
|
||||
async hasOwnedAttribute(type, name) {
|
||||
return !!await this.getOwnedAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
@@ -419,7 +470,7 @@ class Note extends Entity {
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
|
||||
* @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getAttributeValue(type, name) {
|
||||
const attr = await this.getAttribute(type, name);
|
||||
@@ -427,6 +478,17 @@ class Note extends Entity {
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getOwnedAttributeValue(type, name) {
|
||||
const attr = await this.getOwnedAttribute(type, name);
|
||||
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, attribute is either set or removed.
|
||||
*
|
||||
@@ -454,7 +516,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setAttribute(type, name, value) {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
const attributes = await this.loadOwnedAttributesToCache();
|
||||
let attr = attributes.find(attr => attr.type === type && attr.name === name);
|
||||
|
||||
if (attr) {
|
||||
@@ -488,10 +550,10 @@ class Note extends Entity {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async removeAttribute(type, name, value) {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
const attributes = await this.loadOwnedAttributesToCache();
|
||||
|
||||
for (const attribute of attributes) {
|
||||
if (attribute.type === type && (value === undefined || value === attribute.value)) {
|
||||
if (attribute.type === type && attribute.name === name && (value === undefined || value === attribute.value)) {
|
||||
attribute.isDeleted = true;
|
||||
await attribute.save();
|
||||
|
||||
@@ -500,42 +562,104 @@ class Note extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<Attribute>}
|
||||
*/
|
||||
async addAttribute(type, name, value = "") {
|
||||
const attr = new Attribute({
|
||||
noteId: this.noteId,
|
||||
type: type,
|
||||
name: name,
|
||||
value: value
|
||||
});
|
||||
|
||||
await attr.save();
|
||||
|
||||
this.invalidateAttributeCache();
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
async addLabel(name, value = "") {
|
||||
return await this.addAttribute(LABEL, name, value);
|
||||
}
|
||||
|
||||
async addRelation(name, targetNoteId) {
|
||||
return await this.addAttribute(RELATION, name, targetNoteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (including inherited)
|
||||
*/
|
||||
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (excluding inherited)
|
||||
*/
|
||||
async hasOwnedLabel(name) { return await this.hasOwnedAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (including inherited)
|
||||
*/
|
||||
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (excluding inherited)
|
||||
*/
|
||||
async hasOwnedRelation(name) { return await this.hasOwnedAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute>} label if it exists, null otherwise
|
||||
* @returns {Promise<Attribute|null>} label if it exists, null otherwise
|
||||
*/
|
||||
async getLabel(name) { return await this.getAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute|null>} label if it exists, null otherwise
|
||||
*/
|
||||
async getOwnedLabel(name) { return await this.getOwnedAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute>} relation if it exists, null otherwise
|
||||
* @returns {Promise<Attribute|null>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getRelation(name) { return await this.getAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute|null>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getOwnedRelation(name) { return await this.getOwnedAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string>} label value if label exists, null otherwise
|
||||
* @returns {Promise<string|null>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string|null>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getOwnedLabelValue(name) { return await this.getOwnedAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string>} relation value if relation exists, null otherwise
|
||||
* @returns {Promise<string|null>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string|null>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getOwnedRelationValue(name) { return await this.getOwnedAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
@@ -546,6 +670,16 @@ class Note extends Entity {
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getOwnedRelationTarget(name) {
|
||||
const relation = await this.getOwnedRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, label is either set or removed.
|
||||
*
|
||||
@@ -699,7 +833,7 @@ class Note extends Entity {
|
||||
WHERE noteId = ? AND
|
||||
isDeleted = 0 AND
|
||||
type = 'relation' AND
|
||||
name IN ('internal-link', 'image-link', 'relation-map-link')`, [this.noteId]);
|
||||
name IN ('internalLink', 'imageLink', 'relationMapLink')`, [this.noteId]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -776,6 +910,16 @@ class Note extends Entity {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ancestorNoteId
|
||||
* @return {Promise<boolean>} - true if ancestorNoteId occurs in at least one of the note's paths
|
||||
*/
|
||||
async isDescendantOfNote(ancestorNoteId) {
|
||||
const notePaths = await this.getAllNotePaths();
|
||||
|
||||
return notePaths.some(path => path.includes(ancestorNoteId));
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
if (!this.isDeleted) {
|
||||
this.isDeleted = false;
|
||||
@@ -815,7 +959,9 @@ class Note extends Entity {
|
||||
|
||||
delete pojo.isContentAvailable;
|
||||
delete pojo.__attributeCache;
|
||||
delete pojo.__ownedAttributeCache;
|
||||
delete pojo.content;
|
||||
/** zero references to contentHash, probably can be removed */
|
||||
delete pojo.contentHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,313 @@
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="CreateNewNoteParams">CreateNewNoteParams</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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>parentNoteId</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">MANDATORY</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>title</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">MANDATORY</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>content</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
|
||||
|
||||
<span class="param-type">buffer</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">MANDATORY</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>type</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">text, code, file, image, search, book, relation-map - MANDATORY</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>mime</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">value is derived from default mimes for type</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>isProtected</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">boolean</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">default is false</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>isExpanded</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">boolean</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">default is false</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>prefix</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">default is empty string</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>notePosition</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">int</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">default is last existing notePosition in a parent + 10</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line212">line 212</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="CreateNoteAttribute">CreateNoteAttribute</h4>
|
||||
|
||||
|
||||
@@ -290,6 +597,194 @@
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="CreateNoteAttribute">CreateNoteAttribute</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
<th>Attributes</th>
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>type</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">attribute type - label, relation etc.</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>name</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">attribute name</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>value</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">attribute value</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line233">line 233</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="CreateNoteExtraOptions">CreateNoteExtraOptions</h4>
|
||||
|
||||
|
||||
@@ -558,7 +1053,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line180">line 180</a>
|
||||
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line240">line 240</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -198,6 +198,66 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
*/
|
||||
this.toggleNoteInParent = cloningService.toggleNoteInParent;
|
||||
|
||||
/**
|
||||
* @typedef {object} CreateNoteAttribute
|
||||
* @property {string} type - attribute type - label, relation etc.
|
||||
* @property {string} name - attribute name
|
||||
* @property {string} [value] - attribute value
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create text note. See also createNewNote() for more options.
|
||||
*
|
||||
* @param {string} parentNoteId
|
||||
* @param {string} title
|
||||
* @param {string} content
|
||||
* @return {Promise<{note: Note, branch: Branch}>}
|
||||
*/
|
||||
this.createTextNote = async (parentNoteId, title, content = '') => await noteService.createNewNote({
|
||||
parentNoteId,
|
||||
title,
|
||||
content,
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
/**
|
||||
* Create data note - data in this context means object serializable to JSON. Created note will be of type 'code' and
|
||||
* JSON MIME type. See also createNewNote() for more options.
|
||||
*
|
||||
* @param {string} parentNoteId
|
||||
* @param {string} title
|
||||
* @param {object} content
|
||||
* @return {Promise<{note: Note, branch: Branch}>}
|
||||
*/
|
||||
this.createDataNote = async (parentNoteId, title, content = {}) => await noteService.createNewNote({
|
||||
parentNoteId,
|
||||
title,
|
||||
content: JSON.stringify(content, null, '\t'),
|
||||
type: 'code',
|
||||
mime: 'application/json'
|
||||
});
|
||||
|
||||
/**
|
||||
* @typedef {object} CreateNewNoteParams
|
||||
* @property {string} parentNoteId - MANDATORY
|
||||
* @property {string} title - MANDATORY
|
||||
* @property {string|buffer} content - MANDATORY
|
||||
* @property {string} type - text, code, file, image, search, book, relation-map - MANDATORY
|
||||
* @property {string} mime - value is derived from default mimes for type
|
||||
* @property {boolean} isProtected - default is false
|
||||
* @property {boolean} isExpanded - default is false
|
||||
* @property {string} prefix - default is empty string
|
||||
* @property {int} notePosition - default is last existing notePosition in a parent + 10
|
||||
*/
|
||||
|
||||
/**
|
||||
* @method
|
||||
*
|
||||
* @param {CreateNewNoteParams} [params]
|
||||
* @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
|
||||
*/
|
||||
this.createNewNote = noteService.createNewNote;
|
||||
|
||||
/**
|
||||
* @typedef {object} CreateNoteAttribute
|
||||
* @property {string} type - attribute type - label, relation etc.
|
||||
@@ -223,25 +283,38 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
* @param {CreateNoteExtraOptions} [extraOptions={}]
|
||||
* @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
|
||||
*/
|
||||
this.createNote = noteService.createNote;
|
||||
this.createNote = async (parentNoteId, title, content = "", extraOptions= {}) => {
|
||||
extraOptions.parentNoteId = parentNoteId;
|
||||
extraOptions.title = title;
|
||||
|
||||
/**
|
||||
* Creates new note according to given params and force all connected clients to refresh their tree.
|
||||
*
|
||||
* @method
|
||||
*
|
||||
* @param {string} parentNoteId - create new note under this parent
|
||||
* @param {string} title
|
||||
* @param {string} [content=""]
|
||||
* @param {CreateNoteExtraOptions} [extraOptions={}]
|
||||
* @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
|
||||
*/
|
||||
this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) {
|
||||
const ret = await noteService.createNote(parentNoteId, title, content, extraOptions);
|
||||
const parentNote = await repository.getNote(parentNoteId);
|
||||
|
||||
ws.refreshTree();
|
||||
|
||||
return ret;
|
||||
// code note type can be inherited, otherwise text is default
|
||||
extraOptions.type = parentNote.type === 'code' ? 'code' : 'text';
|
||||
extraOptions.mime = parentNote.type === 'code' ? parentNote.mime : 'text/html';
|
||||
|
||||
if (extraOptions.json) {
|
||||
extraOptions.content = JSON.stringify(content || {}, null, '\t');
|
||||
extraOptions.type = 'code';
|
||||
extraOptions.mime = 'application/json';
|
||||
}
|
||||
else {
|
||||
extraOptions.content = content;
|
||||
}
|
||||
|
||||
const {note, branch} = await noteService.createNewNote(extraOptions);
|
||||
|
||||
for (const attr of extraOptions.attributes || []) {
|
||||
await attributeService.createAttribute({
|
||||
noteId: note.noteId,
|
||||
type: attr.type,
|
||||
name: attr.name,
|
||||
value: attr.value,
|
||||
isInheritable: !!attr.isInheritable
|
||||
});
|
||||
}
|
||||
|
||||
return {note, branch};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -268,6 +341,14 @@ function BackendScriptApi(currentNote, apiParams) {
|
||||
*/
|
||||
this.getDateNote = dateNoteService.getDateNote;
|
||||
|
||||
/**
|
||||
* Returns today's day note. If such note doesn't exist, it is created.
|
||||
*
|
||||
* @method
|
||||
* @returns {Promise<Note|null>}
|
||||
*/
|
||||
this.getTodayNote = dateNoteService.getTodayNote;
|
||||
|
||||
/**
|
||||
* Returns note for the first date of the week of the given date.
|
||||
*
|
||||
|
||||
@@ -241,7 +241,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line17">line 17</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line16">line 16</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -357,7 +357,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line13">line 13</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line12">line 12</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -415,7 +415,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line11">line 11</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line10">line 10</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -473,7 +473,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line15">line 15</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line14">line 14</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -549,7 +549,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line21">line 21</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line20">line 20</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -651,7 +651,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line26">line 26</a>
|
||||
<a href="entities_branch.js.html">entities/branch.js</a>, <a href="entities_branch.js.html#line25">line 25</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -807,7 +807,7 @@
|
||||
|
||||
|
||||
<div class="description">
|
||||
Activates newly created note. Compared to this.activateNote() also refreshes tree.
|
||||
Activates newly created note. Compared to this.activateNote() also makes sure that frontend has been fully synced.
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1240,6 +1240,143 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="addTextToActiveTabEditor"><span class="type-signature"></span>addTextToActiveTabEditor<span class="signature">(text)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Adds given text to the editor cursor
|
||||
</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>text</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></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#line305">line 305</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1366,7 +1503,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line384">line 384</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line406">line 406</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1546,7 +1683,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line291">line 291</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line297">line 297</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1679,7 +1816,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line235">line 235</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line241">line 241</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1785,7 +1922,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line297">line 297</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line311">line 311</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1891,7 +2028,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line303">line 303</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line325">line 325</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1949,6 +2086,119 @@
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="getActiveTabTextEditor"><span class="type-signature"></span>getActiveTabTextEditor<span class="signature">()</span><span class="type-signature"> → {Editor|null}</span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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#line319">line 319</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
<div class="param-desc">
|
||||
CKEditor instance or null (e.g. if active note is not a text note)
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<span class="param-type">Editor</span>
|
||||
|
|
||||
|
||||
<span class="param-type">null</span>
|
||||
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="getDateNote"><span class="type-signature"></span>getDateNote<span class="signature">(date)</span><span class="type-signature"> → {Promise.<<a href="NoteShort.html">NoteShort</a>>}</span></h4>
|
||||
|
||||
|
||||
@@ -2050,7 +2300,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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#line372">line 372</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2157,7 +2407,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line228">line 228</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line234">line 234</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2312,7 +2562,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line359">line 359</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line381">line 381</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2468,7 +2718,7 @@ if some action needs to happen on only one specific instance.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line200">line 200</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line206">line 206</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2669,7 +2919,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line212">line 212</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>
|
||||
|
||||
|
||||
@@ -2775,7 +3025,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#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#line363">line 363</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2930,7 +3180,7 @@ otherwise (by e.g. createNoteLink())
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line368">line 368</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line390">line 390</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3039,7 +3289,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line314">line 314</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line336">line 336</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3194,7 +3444,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line322">line 322</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line344">line 344</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3327,7 +3577,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line242">line 242</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line248">line 248</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3433,7 +3683,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line333">line 333</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line355">line 355</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3521,7 +3771,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line274">line 274</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line280">line 280</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3627,7 +3877,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line282">line 282</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line288">line 288</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3733,7 +3983,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line266">line 266</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line272">line 272</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3888,7 +4138,7 @@ note.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line220">line 220</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line226">line 226</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3924,7 +4174,7 @@ note.
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="runOnServer"><span class="type-signature"></span>runOnServer<span class="signature">(script, params)</span><span class="type-signature"> → {Promise.<*>}</span></h4>
|
||||
<h4 class="name" id="runOnBackend"><span class="type-signature"></span>runOnBackend<span class="signature">(script, params)</span><span class="type-signature"> → {Promise.<*>}</span></h4>
|
||||
|
||||
|
||||
|
||||
@@ -3932,7 +4182,7 @@ note.
|
||||
|
||||
|
||||
<div class="description">
|
||||
Executes given anonymous function on the server.
|
||||
Executes given anonymous function on the backend.
|
||||
Internally this serializes the anonymous function into string and sends it to backend via AJAX.
|
||||
</div>
|
||||
|
||||
@@ -4101,6 +4351,92 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="runOnServer"><span class="type-signature"></span>runOnServer<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="important tag-deprecated">Deprecated:</dt><dd><ul class="dummy"><li>new name of this API call is runOnBackend so use that</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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#line166">line 166</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4209,7 +4545,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line188">line 188</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line194">line 194</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4365,7 +4701,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line170">line 170</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line176">line 176</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4520,7 +4856,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line377">line 377</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line399">line 399</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4671,7 +5007,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line328">line 328</a>
|
||||
<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>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4808,7 +5144,7 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line258">line 258</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line264">line 264</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4945,7 +5281,99 @@ Internally this serializes the anonymous function into string and sends it to ba
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line250">line 250</a>
|
||||
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line256">line 256</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="waitUntilSynced"><span class="type-signature"></span>waitUntilSynced<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
Trilium runs in backend and frontend process, when something is changed on the backend from script,
|
||||
frontend will get asynchronously synchronized.
|
||||
|
||||
This method returns a promise which resolves once all the backend -> frontend synchronization is finished.
|
||||
Typical use case is when new note has been created, we should wait until it is synced into frontend and only then activate it.
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<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#line417">line 417</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
2266
docs/frontend_api/KeyboardAction.html
Normal file
2266
docs/frontend_api/KeyboardAction.html
Normal file
File diff suppressed because it is too large
Load Diff
280
docs/frontend_api/KeyboardActions.html
Normal file
280
docs/frontend_api/KeyboardActions.html
Normal file
@@ -0,0 +1,280 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: KeyboardActions</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: KeyboardActions</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>KeyboardActions<span class="signature">()</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">blaa vlaa</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="KeyboardActions"><span class="type-signature"></span>new KeyboardActions<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_keyboard_actions.js.html">services/keyboard_action.js</a>, <a href="services_keyboard_actions.js.html#line5">line 5</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="JUMP_TO"><span class="type-signature"></span>JUMP_TO<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_keyboard_actions.js.html">services/keyboard_action.js</a>, <a href="services_keyboard_actions.js.html#line7">line 7</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="KeyboardActions.html">KeyboardActions</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1220,7 +1220,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line220">line 220</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line227">line 227</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1278,7 +1278,7 @@
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="getAttributes"><span class="type-signature">(async) </span>getAttributes<span class="signature">(name<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<Array.<<a href="Attribute.html">Attribute</a>>>}</span></h4>
|
||||
<h4 class="name" id="getAttributes"><span class="type-signature">(async) </span>getAttributes<span class="signature">(type<span class="signature-attributes">opt</span>, name<span class="signature-attributes">opt</span>)</span><span class="type-signature"> → {Promise.<Array.<<a href="Attribute.html">Attribute</a>>>}</span></h4>
|
||||
|
||||
|
||||
|
||||
@@ -1318,6 +1318,39 @@
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>type</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
<td class="attributes">
|
||||
|
||||
<optional><br>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last">(optional) attribute type to filter</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>name</code></td>
|
||||
@@ -1346,7 +1379,7 @@
|
||||
|
||||
|
||||
|
||||
<td class="description last">attribute name to filter</td>
|
||||
<td class="description last">(optional) attribute name to filter</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -1387,7 +1420,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line160">line 160</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line161">line 161</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -1415,6 +1448,10 @@
|
||||
<h5>Returns:</h5>
|
||||
|
||||
|
||||
<div class="param-desc">
|
||||
all note's attributes, including inherited ones
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<dl>
|
||||
@@ -1561,7 +1598,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line231">line 231</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line238">line 238</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2124,7 +2161,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line253">line 253</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>
|
||||
|
||||
|
||||
@@ -2291,7 +2328,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line186">line 186</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line193">line 193</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2458,7 +2495,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line178">line 178</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line185">line 185</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2613,7 +2650,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line265">line 265</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line272">line 272</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -2972,7 +3009,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line259">line 259</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line266">line 266</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3139,7 +3176,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line202">line 202</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line209">line 209</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3306,7 +3343,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line194">line 194</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line201">line 201</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3461,7 +3498,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line277">line 277</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line284">line 284</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3631,7 +3668,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line287">line 287</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line294">line 294</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3782,7 +3819,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line271">line 271</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line278">line 278</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -3892,7 +3929,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line311">line 311</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line318">line 318</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4066,7 +4103,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line211">line 211</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line218">line 218</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4323,7 +4360,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line241">line 241</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line248">line 248</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4478,7 +4515,7 @@
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line247">line 247</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line254">line 254</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
@@ -4536,7 +4573,7 @@
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="invalidateAttributeCache"><span class="type-signature"></span>invalidateAttributeCache<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
<h4 class="name" id="invalidate__attributeCache"><span class="type-signature"></span>invalidate__attributeCache<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
@@ -4589,7 +4626,7 @@ Cache is note instance scoped.
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line302">line 302</a>
|
||||
<a href="entities_note_short.js.html">entities/note_short.js</a>, <a href="entities_note_short.js.html#line309">line 309</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ class Branch {
|
||||
this.branchId = row.branchId;
|
||||
/** @param {string} */
|
||||
this.noteId = row.noteId;
|
||||
this.note = null;
|
||||
/** @param {string} */
|
||||
this.parentNoteId = row.parentNoteId;
|
||||
/** @param {int} */
|
||||
@@ -47,7 +46,7 @@ class Branch {
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
async getNote() {
|
||||
return await this.treeCache.getNote(this.noteId);
|
||||
return this.treeCache.getNote(this.noteId);
|
||||
}
|
||||
|
||||
/** @returns {boolean} true if it's top level, meaning its parent is root note */
|
||||
|
||||
@@ -182,20 +182,27 @@ class NoteShort {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @returns {Promise<Attribute[]>}
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
if (!this.attributeCache) {
|
||||
this.attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
|
||||
async getAttributes(type, name) {
|
||||
if (!this.__attributeCache) {
|
||||
this.__attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
|
||||
.map(attrRow => new Attribute(this.treeCache, attrRow));
|
||||
}
|
||||
|
||||
if (name) {
|
||||
return this.attributeCache.filter(attr => attr.name === name);
|
||||
if (type && name) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.attributeCache;
|
||||
return this.__attributeCache.slice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +211,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
return await this.getAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +219,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
return await this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,7 +227,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
return await this.getAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,7 +235,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
return await this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,8 +334,8 @@ class NoteShort {
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.attributeCache = null;
|
||||
invalidate__attributeCache() {
|
||||
this.__attributeCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +356,7 @@ class NoteShort {
|
||||
const dto = Object.assign({}, this);
|
||||
delete dto.treeCache;
|
||||
delete dto.archived;
|
||||
delete dto.attributeCache;
|
||||
delete dto.__attributeCache;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
280
docs/frontend_api/module.exports.html
Normal file
280
docs/frontend_api/module.exports.html
Normal file
@@ -0,0 +1,280 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Class: exports</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Class: exports</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2><span class="attribs"><span class="type-signature"></span></span>exports<span class="signature">()</span><span class="type-signature"></span></h2>
|
||||
|
||||
<div class="class-description">blaa vlaa</div>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
<h2>Constructor</h2>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="exports"><span class="type-signature"></span>new exports<span class="signature">()</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_keyboard_actions.js.html">services/keyboard_action.js</a>, <a href="services_keyboard_actions.js.html#line5">line 5</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="JUMP_TO"><span class="type-signature"></span>JUMP_TO<span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">string</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="services_keyboard_actions.js.html">services/keyboard_action.js</a>, <a href="services_keyboard_actions.js.html#line7">line 7</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="module.exports.html">exports</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -86,13 +86,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
};
|
||||
|
||||
/**
|
||||
* Activates newly created note. Compared to this.activateNote() also refreshes tree.
|
||||
* Activates newly created note. Compared to this.activateNote() also makes sure that frontend has been fully synced.
|
||||
*
|
||||
* @param {string} notePath (or noteId)
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
this.activateNewNote = async notePath => {
|
||||
await treeService.reload();
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
||||
await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
|
||||
};
|
||||
@@ -153,14 +153,14 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given anonymous function on the server.
|
||||
* Executes given anonymous function on the backend.
|
||||
* Internally this serializes the anonymous function into string and sends it to backend via AJAX.
|
||||
*
|
||||
* @param {string} script - script to be executed on the backend
|
||||
* @param {Array.<?>} params - list of parameters to the anonymous function to be send to backend
|
||||
* @return {Promise<*>} return value of the executed function on the backend
|
||||
*/
|
||||
this.runOnServer = async (script, params = []) => {
|
||||
this.runOnBackend = async (script, params = []) => {
|
||||
if (typeof script === "function") {
|
||||
script = script.toString();
|
||||
}
|
||||
@@ -187,6 +187,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated new name of this API call is runOnBackend so use that
|
||||
* @method
|
||||
*/
|
||||
this.runOnServer = this.runOnBackend;
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
@@ -318,12 +324,28 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
*/
|
||||
this.createNoteLink = linkService.createNoteLink;
|
||||
|
||||
/**
|
||||
* Adds given text to the editor cursor
|
||||
*
|
||||
* @param {string} text
|
||||
* @method
|
||||
*/
|
||||
this.addTextToActiveTabEditor = linkService.addTextToEditor;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @returns {NoteFull} active note (loaded into right pane)
|
||||
*/
|
||||
this.getActiveTabNote = noteDetailService.getActiveTabNote;
|
||||
|
||||
/**
|
||||
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
||||
*
|
||||
* @method
|
||||
* @returns {Editor|null} CKEditor instance or null (e.g. if active note is not a text note)
|
||||
*/
|
||||
this.getActiveTabTextEditor = noteDetailService.getActiveEditor;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
||||
@@ -410,6 +432,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
* @param {function} handler
|
||||
*/
|
||||
this.bindGlobalShortcut = utils.bindGlobalShortcut;
|
||||
|
||||
/**
|
||||
* Trilium runs in backend and frontend process, when something is changed on the backend from script,
|
||||
* frontend will get asynchronously synchronized.
|
||||
*
|
||||
* This method returns a promise which resolves once all the backend -> frontend synchronization is finished.
|
||||
* Typical use case is when new note has been created, we should wait until it is synced into frontend and only then activate it.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
this.waitUntilSynced = ws.waitForMaxKnownSyncId;
|
||||
}
|
||||
|
||||
export default FrontendScriptApi;</code></pre>
|
||||
|
||||
280
docs/frontend_api/services_keyboard_action.js.html
Normal file
280
docs/frontend_api/services_keyboard_action.js.html
Normal file
@@ -0,0 +1,280 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: services/keyboard_action.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: services/keyboard_action.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/**
|
||||
* blaa vlaa
|
||||
*/
|
||||
class KeyboardAction {
|
||||
constructor(params) {
|
||||
this.optionName = params.optionName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open "Jump to note" dialog
|
||||
* @static
|
||||
*/
|
||||
KeyboardAction.JumpToNote = new KeyboardAction({
|
||||
optionName: "JumpToNote",
|
||||
defaultShortcuts: "mod+j",
|
||||
description: 'Open "Jump to note" dialog'
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.MarkdownToHTML = new KeyboardAction({
|
||||
optionName: "MarkdownToHTML",
|
||||
defaultShortcuts: "mod+return"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.NewTab = new KeyboardAction({
|
||||
optionName: "NewTab",
|
||||
defaultShortcuts: "mod+t"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.CloseTab = new KeyboardAction({
|
||||
optionName: "CloseTab",
|
||||
defaultShortcuts: "mod+w"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.NextTab = new KeyboardAction({
|
||||
optionName: "NextTab",
|
||||
defaultShortcuts: "mod+tab"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.PreviousTab = new KeyboardAction({
|
||||
optionName: "PreviousTab",
|
||||
defaultShortcuts: "mod+shift+tab"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.CreateNoteAfter = new KeyboardAction({
|
||||
optionName: "CreateNoteAfter",
|
||||
defaultShortcuts: "mod+o"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.CreateNoteInto = new KeyboardAction({
|
||||
optionName: "CreateNoteInto",
|
||||
defaultShortcuts: "mod+p"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ScrollToActiveNote = new KeyboardAction({
|
||||
optionName: "ScrollToActiveNote",
|
||||
defaultShortcuts: "mod+."
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.CollapseTree = new KeyboardAction({
|
||||
optionName: "CollapseTree",
|
||||
defaultShortcuts: "alt+c"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.RunSQL = new KeyboardAction({
|
||||
optionName: "RunSQL",
|
||||
defaultShortcuts: "mod+return"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.FocusNote = new KeyboardAction({
|
||||
optionName: "FocusNote",
|
||||
defaultShortcuts: "return"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.RunCurrentNote = new KeyboardAction({
|
||||
optionName: "RunCurrentNote",
|
||||
defaultShortcuts: "mod+return"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ClipboardCopy = new KeyboardAction({
|
||||
optionName: "ClipboardCopy",
|
||||
defaultShortcuts: "mod+c"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ClipboardPaste = new KeyboardAction({
|
||||
optionName: "ClipboardPaste",
|
||||
defaultShortcuts: "mod+v"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ClipboardCut = new KeyboardAction({
|
||||
optionName: "ClipboardCut",
|
||||
defaultShortcuts: "mod+x"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.SelectAllNotesInParent = new KeyboardAction({
|
||||
optionName: "SelectAllNotesInParent",
|
||||
defaultShortcuts: "mod+a"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.Undo = new KeyboardAction({
|
||||
optionName: "Undo",
|
||||
defaultShortcuts: "mod+z"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.Redo = new KeyboardAction({
|
||||
optionName: "Redo",
|
||||
defaultShortcuts: "mod+y"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.AddLinkToText = new KeyboardAction({
|
||||
optionName: "AddLinkToText",
|
||||
defaultShortcuts: "mod+l"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.CloneNotesTo = new KeyboardAction({
|
||||
optionName: "CloneNotesTo",
|
||||
defaultShortcuts: "mod+shift+c"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.MoveNotesTo = new KeyboardAction({
|
||||
optionName: "MoveNotesTo",
|
||||
defaultShortcuts: "mod+shift+c"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.SearchNotes = new KeyboardAction({
|
||||
optionName: "SearchNotes",
|
||||
defaultShortcuts: "mod+s"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ShowAttributes = new KeyboardAction({
|
||||
optionName: "ShowAttributes",
|
||||
defaultShortcuts: "alt+a"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ShowHelp = new KeyboardAction({
|
||||
optionName: "ShowHelp",
|
||||
defaultShortcuts: "f1"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.OpenSQLConsole = new KeyboardAction({
|
||||
optionName: "OpenSQLConsole",
|
||||
defaultShortcuts: "alt+o"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.BackInNoteHistory = new KeyboardAction({
|
||||
optionName: "BackInNoteHistory",
|
||||
defaultShortcuts: "alt+left"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ForwardInNoteHistory = new KeyboardAction({
|
||||
optionName: "ForwardInNoteHistory",
|
||||
defaultShortcuts: "alt+right"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ToggleZenMode = new KeyboardAction({
|
||||
optionName: "ToggleZenMode",
|
||||
defaultShortcuts: "alt+m"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.InsertDateTime = new KeyboardAction({
|
||||
optionName: "InsertDateTime",
|
||||
defaultShortcuts: "alt+t"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ReloadApp = new KeyboardAction({
|
||||
optionName: "ReloadApp",
|
||||
defaultShortcuts: ["f5", "mod+r"]
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.OpenDevTools = new KeyboardAction({
|
||||
optionName: "OpenDevTools",
|
||||
defaultShortcuts: "mod+shift+i"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.FindInText = new KeyboardAction({
|
||||
optionName: "FindInText",
|
||||
defaultShortcuts: "mod+f"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ToggleFullscreen = new KeyboardAction({
|
||||
optionName: "ToggleFullscreen",
|
||||
defaultShortcuts: "f11"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ZoomOut = new KeyboardAction({
|
||||
optionName: "ZoomOut",
|
||||
defaultShortcuts: "mod+-"
|
||||
});
|
||||
|
||||
/** @static */
|
||||
KeyboardAction.ZoomIn = new KeyboardAction({
|
||||
optionName: "ZoomIn",
|
||||
defaultShortcuts: "mod+="
|
||||
});
|
||||
|
||||
export default KeyboardAction;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="KeyboardAction.html">KeyboardAction</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
61
docs/frontend_api/services_keyboard_actions.js.html
Normal file
61
docs/frontend_api/services_keyboard_actions.js.html
Normal file
@@ -0,0 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>JSDoc: Source: services/keyboard_action.js</title>
|
||||
|
||||
<script src="scripts/prettify/prettify.js"> </script>
|
||||
<script src="scripts/prettify/lang-css.js"> </script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<h1 class="page-title">Source: services/keyboard_action.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>/**
|
||||
* blaa vlaa
|
||||
*/
|
||||
class KeyboardActions {
|
||||
constructor() {
|
||||
/** @property {string} */
|
||||
this.JUMP_TO = "";
|
||||
}
|
||||
}
|
||||
|
||||
export default KeyboardActions;</code></pre>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="KeyboardActions.html">KeyboardActions</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
|
||||
</nav>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
<footer>
|
||||
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a>
|
||||
</footer>
|
||||
|
||||
<script> prettyPrint(); </script>
|
||||
<script src="scripts/linenumber.js"> </script>
|
||||
</body>
|
||||
</html>
|
||||
98
electron.js
98
electron.js
@@ -1,85 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const {app, globalShortcut, BrowserWindow} = require('electron');
|
||||
const path = require('path');
|
||||
const log = require('./src/services/log');
|
||||
const {app, globalShortcut} = require('electron');
|
||||
const sqlInit = require('./src/services/sql_init');
|
||||
const cls = require('./src/services/cls');
|
||||
const url = require("url");
|
||||
const port = require('./src/services/port');
|
||||
const env = require('./src/services/env');
|
||||
const appIconService = require('./src/services/app_icon');
|
||||
const windowStateKeeper = require('electron-window-state');
|
||||
const windowService = require('./src/services/window');
|
||||
|
||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||
require('electron-debug')();
|
||||
|
||||
appIconService.installLocalAppIcon();
|
||||
|
||||
// Prevent window being garbage collected
|
||||
let mainWindow;
|
||||
|
||||
require('electron-dl')({ saveAs: true });
|
||||
|
||||
function onClosed() {
|
||||
// Dereference the window
|
||||
// For multiple windows store them in an array
|
||||
mainWindow = null;
|
||||
}
|
||||
|
||||
async function createMainWindow() {
|
||||
await sqlInit.dbConnection;
|
||||
|
||||
// if schema doesn't exist -> setup process
|
||||
// if schema exists, then we need to wait until the migration process is finished
|
||||
if (await sqlInit.schemaExists()) {
|
||||
await sqlInit.dbReady;
|
||||
}
|
||||
|
||||
const mainWindowState = windowStateKeeper({
|
||||
// default window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
|
||||
defaultWidth: 1200,
|
||||
defaultHeight: 800
|
||||
});
|
||||
|
||||
const win = new BrowserWindow({
|
||||
x: mainWindowState.x,
|
||||
y: mainWindowState.y,
|
||||
width: mainWindowState.width,
|
||||
height: mainWindowState.height,
|
||||
title: 'Trilium Notes',
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
},
|
||||
icon: path.join(__dirname, 'images/app-icons/png/256x256' + (env.isDev() ? '-dev' : '') + '.png')
|
||||
});
|
||||
|
||||
mainWindowState.manage(win);
|
||||
|
||||
win.setMenuBarVisibility(false);
|
||||
win.loadURL('http://127.0.0.1:' + await port);
|
||||
win.on('closed', onClosed);
|
||||
|
||||
win.webContents.on('new-window', (e, url) => {
|
||||
if (url !== win.webContents.getURL()) {
|
||||
e.preventDefault();
|
||||
require('electron').shell.openExternal(url);
|
||||
}
|
||||
});
|
||||
|
||||
// prevent drag & drop to navigate away from trilium
|
||||
win.webContents.on('will-navigate', (ev, targetUrl) => {
|
||||
const parsedUrl = url.parse(targetUrl);
|
||||
|
||||
// we still need to allow internal redirects from setup and migration pages
|
||||
if (!['localhost', '127.0.0.1'].includes(parsedUrl.hostname) || (parsedUrl.path && parsedUrl.path !== '/')) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
@@ -89,27 +21,23 @@ app.on('window-all-closed', () => {
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', () => {
|
||||
if (!mainWindow) {
|
||||
mainWindow = createMainWindow();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('ready', async () => {
|
||||
app.setAppUserModelId('com.github.zadam.trilium');
|
||||
|
||||
mainWindow = await createMainWindow();
|
||||
await sqlInit.dbConnection;
|
||||
|
||||
const result = globalShortcut.register('CommandOrControl+Alt+P', cls.wrap(async () => {
|
||||
// window may be hidden / not in focus
|
||||
mainWindow.focus();
|
||||
// if db is not initialized -> setup process
|
||||
// if db is initialized, then we need to wait until the migration process is finished
|
||||
if (await sqlInit.isDbInitialized()) {
|
||||
await sqlInit.dbReady;
|
||||
|
||||
mainWindow.webContents.send('create-day-sub-note');
|
||||
}));
|
||||
|
||||
if (!result) {
|
||||
log.error("Could not register global shortcut CTRL+ALT+P");
|
||||
await windowService.createMainWindow();
|
||||
}
|
||||
else {
|
||||
await windowService.createSetupWindow();
|
||||
}
|
||||
|
||||
await windowService.registerGlobalShortcuts();
|
||||
});
|
||||
|
||||
app.on('will-quit', () => {
|
||||
|
||||
4
libraries/bootstrap/css/bootstrap.min.css
vendored
4
libraries/bootstrap/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
310
libraries/ckeditor/ckeditor-content.css
Normal file
310
libraries/ckeditor/ckeditor-content.css
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* !!!!!!! This stylesheet is heavily modified compared to the original for similarity with in-editor look !!!!!!!
|
||||
* This is used for printing and tar HTML export
|
||||
*
|
||||
* CKEditor 5 (v15.0.0) content styles.
|
||||
* Generated on Wed, 27 Nov 2019 13:26:13 GMT.
|
||||
* For more information, check out https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html
|
||||
*/
|
||||
|
||||
:root {
|
||||
--ck-highlight-marker-blue: #72cdfd;
|
||||
--ck-highlight-marker-green: #63f963;
|
||||
--ck-highlight-marker-pink: #fc7999;
|
||||
--ck-highlight-marker-yellow: #fdfd77;
|
||||
--ck-highlight-pen-green: #118800;
|
||||
--ck-highlight-pen-red: #e91313;
|
||||
--ck-image-style-spacing: 1.5em;
|
||||
--ck-todo-list-checkmark-size: 16px;
|
||||
font-family: Arial, Sans-Serif;
|
||||
}
|
||||
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list {
|
||||
list-style: none;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list li {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list li .todo-list {
|
||||
margin-top: 5px;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input {
|
||||
-webkit-appearance: none;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: var(--ck-todo-list-checkmark-size);
|
||||
height: var(--ck-todo-list-checkmark-size);
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
left: -25px;
|
||||
margin-right: -15px;
|
||||
right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input::before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid hsl(0, 0%, 20%);
|
||||
border-radius: 2px;
|
||||
transition: 250ms ease-in-out box-shadow, 250ms ease-in-out background, 250ms ease-in-out border;
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input::after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
pointer-events: none;
|
||||
content: '';
|
||||
left: calc( var(--ck-todo-list-checkmark-size) / 3 );
|
||||
top: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
||||
width: calc( var(--ck-todo-list-checkmark-size) / 5.3 );
|
||||
height: calc( var(--ck-todo-list-checkmark-size) / 2.6 );
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input[checked]::before {
|
||||
border-color: hsl(126, 64%, 41%);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label > input[checked]::after {
|
||||
border-color: hsl(126, 64%, 41%);
|
||||
}
|
||||
/* ckeditor5-list/theme/todolist.css */
|
||||
.todo-list .todo-list__label .todo-list__label__description {
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* ckeditor5-image/theme/image.css */
|
||||
.image {
|
||||
display: table;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
margin: 1em auto;
|
||||
}
|
||||
/* ckeditor5-image/theme/image.css */
|
||||
.image > img {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
min-width: 50px;
|
||||
}
|
||||
/* ckeditor5-block-quote/theme/blockquote.css */
|
||||
blockquote {
|
||||
overflow: hidden;
|
||||
padding-right: 1.5em;
|
||||
padding-left: 1.5em;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
font-style: italic;
|
||||
border-left: solid 5px hsl(0, 0%, 80%);
|
||||
}
|
||||
/* ckeditor5-block-quote/theme/blockquote.css */
|
||||
.ck-content[dir="rtl"] blockquote {
|
||||
border-left: 0;
|
||||
border-right: solid 5px hsl(0, 0%, 80%);
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized {
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized img {
|
||||
width: 100%;
|
||||
}
|
||||
/* ckeditor5-image/theme/imageresize.css */
|
||||
.image.image_resized > figcaption {
|
||||
display: block;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-side,
|
||||
.image-style-align-left,
|
||||
.image-style-align-center,
|
||||
.image-style-align-right {
|
||||
max-width: 50%;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-side {
|
||||
float: right;
|
||||
margin-left: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-left {
|
||||
float: left;
|
||||
margin-right: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagestyle.css */
|
||||
.image-style-align-right {
|
||||
float: right;
|
||||
margin-left: var(--ck-image-style-spacing);
|
||||
}
|
||||
/* ckeditor5-media-embed/theme/mediaembed.css */
|
||||
.media {
|
||||
clear: both;
|
||||
margin: 1em 0;
|
||||
display: block;
|
||||
min-width: 15em;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table {
|
||||
display: table;
|
||||
margin: 0;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border: 1px double hsl(0, 0%, 70%);
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table td,
|
||||
.table table th {
|
||||
min-width: 2em;
|
||||
padding: .4em;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
/* ckeditor5-table/theme/table.css */
|
||||
.table table th {
|
||||
font-weight: bold;
|
||||
background-color: #f5f5f5;
|
||||
text-align: left;
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-yellow {
|
||||
background-color: var(--ck-highlight-marker-yellow);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-green {
|
||||
background-color: var(--ck-highlight-marker-green);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-pink {
|
||||
background-color: var(--ck-highlight-marker-pink);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.marker-blue {
|
||||
background-color: var(--ck-highlight-marker-blue);
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.pen-red {
|
||||
color: var(--ck-highlight-pen-red);
|
||||
background-color: transparent;
|
||||
}
|
||||
/* ckeditor5-highlight/theme/highlight.css */
|
||||
.pen-green {
|
||||
color: var(--ck-highlight-pen-green);
|
||||
background-color: transparent;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break {
|
||||
position: relative;
|
||||
clear: both;
|
||||
padding: 5px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
border-bottom: 2px dashed hsl(0, 0%, 77%);
|
||||
width: 100%;
|
||||
}
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break__label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding: .3em .6em;
|
||||
display: block;
|
||||
text-transform: uppercase;
|
||||
border: 1px solid hsl(0, 0%, 77%);
|
||||
border-radius: 2px;
|
||||
font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
color: hsl(0, 0%, 20%);
|
||||
background: #fff;
|
||||
box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15);
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
/* ckeditor5-basic-styles/theme/code.css */
|
||||
code {
|
||||
background-color: hsla(0, 0%, 78%, 0.3);
|
||||
padding: .15em;
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* ckeditor5-image/theme/imagecaption.css */
|
||||
.image > figcaption {
|
||||
display: table-caption;
|
||||
caption-side: bottom;
|
||||
word-break: break-word;
|
||||
color: hsl(0, 0%, 20%);
|
||||
background-color: hsl(0, 0%, 97%);
|
||||
padding: .6em;
|
||||
font-size: .75em;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
/* ckeditor5-horizontal-line/theme/horizontalline.css */
|
||||
hr {
|
||||
border-width: 1px 0 0;
|
||||
border-style: solid;
|
||||
border-color: hsl(0, 0%, 37%);
|
||||
margin: 0;
|
||||
}
|
||||
/* ckeditor5-code-block/theme/codeblock.css */
|
||||
pre {
|
||||
padding: 1em;
|
||||
color: #353535;
|
||||
background: hsla(0, 0%, 78%, 0.3);
|
||||
border: 1px solid hsl(0, 0%, 77%);
|
||||
border-radius: 2px;
|
||||
text-align: left;
|
||||
direction: ltr;
|
||||
tab-size: 4;
|
||||
white-space: pre-wrap;
|
||||
font-style: normal;
|
||||
min-width: 200px;
|
||||
}
|
||||
/* ckeditor5-code-block/theme/codeblock.css */
|
||||
pre code {
|
||||
background: unset;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ck-widget__selection-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* ckeditor5-page-break/theme/pagebreak.css */
|
||||
.page-break::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
4
libraries/ckeditor/ckeditor.js
vendored
4
libraries/ckeditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
164
libraries/ckeditor/inspector.js
Normal file
164
libraries/ckeditor/inspector.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/*! jQuery Fancytree Plugin - 2.33.0 - 2019-10-29T08:00:07Z
|
||||
/*! jQuery Fancytree Plugin - 2.34.0 - 2019-12-26T14:16:19Z
|
||||
* https://github.com/mar10/fancytree
|
||||
* Copyright (c) 2019 Martin Wendt; Licensed MIT
|
||||
*/
|
||||
@@ -1365,8 +1365,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
/** Core Fancytree module.
|
||||
@@ -4156,11 +4156,18 @@ var uniqueId = $.fn.extend( {
|
||||
delete this._tempCache[key];
|
||||
return null;
|
||||
},
|
||||
/* Check if this tree has extension `name` enabled.
|
||||
*
|
||||
* @param {string} name name of the required extension
|
||||
*/
|
||||
_usesExtension: function(name) {
|
||||
return $.inArray(name, this.options.extensions) >= 0;
|
||||
},
|
||||
/* Check if current extensions dependencies are met and throw an error if not.
|
||||
*
|
||||
* This method may be called inside the `treeInit` hook for custom extensions.
|
||||
*
|
||||
* @param {string} extension name of the required extension
|
||||
* @param {string} name name of the required extension
|
||||
* @param {boolean} [required=true] pass `false` if the extension is optional, but we want to check for order if it is present
|
||||
* @param {boolean} [before] `true` if `name` must be included before this, `false` otherwise (use `null` if order doesn't matter)
|
||||
* @param {string} [message] optional error message (defaults to a descriptve error message)
|
||||
@@ -4417,6 +4424,13 @@ var uniqueId = $.fn.extend( {
|
||||
consoleApply("log", arguments);
|
||||
}
|
||||
},
|
||||
/** Destroy this widget, restore previous markup and cleanup resources.
|
||||
*
|
||||
* @since 2.34
|
||||
*/
|
||||
destroy: function() {
|
||||
this.widget.destroy();
|
||||
},
|
||||
/** Enable (or disable) the tree control.
|
||||
*
|
||||
* @param {boolean} [flag=true] pass false to disable
|
||||
@@ -4795,6 +4809,20 @@ var uniqueId = $.fn.extend( {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasFocus: function() {
|
||||
// var ae = document.activeElement,
|
||||
// hasFocus = !!(
|
||||
// ae && $(ae).closest(".fancytree-container").length
|
||||
// );
|
||||
|
||||
// if (hasFocus !== !!this._hasFocus) {
|
||||
// this.warn(
|
||||
// "hasFocus(): fix inconsistent container state, now: " +
|
||||
// hasFocus
|
||||
// );
|
||||
// this._hasFocus = hasFocus;
|
||||
// this.$container.toggleClass("fancytree-treefocus", hasFocus);
|
||||
// }
|
||||
// return hasFocus;
|
||||
return !!this._hasFocus;
|
||||
},
|
||||
/** Write to browser console if debugLevel >= 3 (prepending tree name)
|
||||
@@ -5120,6 +5148,26 @@ var uniqueId = $.fn.extend( {
|
||||
setOption: function(optionName, value) {
|
||||
return this.widget.option(optionName, value);
|
||||
},
|
||||
/**
|
||||
* Call console.time() when in debug mode (verbose >= 4).
|
||||
*
|
||||
* @param {string} label
|
||||
*/
|
||||
debugTime: function(label) {
|
||||
if (this.options.debugLevel >= 4) {
|
||||
window.console.time(this + " - " + label);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Call console.timeEnd() when in debug mode (verbose >= 4).
|
||||
*
|
||||
* @param {string} label
|
||||
*/
|
||||
debugTimeEnd: function(label) {
|
||||
if (this.options.debugLevel >= 4) {
|
||||
window.console.timeEnd(this + " - " + label);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Return all nodes as nested list of {@link NodeData}.
|
||||
*
|
||||
@@ -5185,7 +5233,7 @@ var uniqueId = $.fn.extend( {
|
||||
* @since 2.28
|
||||
*/
|
||||
visitRows: function(fn, opts) {
|
||||
if (!this.rootNode.children) {
|
||||
if (!this.rootNode.hasChildren()) {
|
||||
return false;
|
||||
}
|
||||
if (opts && opts.reverse) {
|
||||
@@ -5314,7 +5362,8 @@ var uniqueId = $.fn.extend( {
|
||||
/**
|
||||
* These additional methods of the {@link Fancytree} class are 'hook functions'
|
||||
* that can be used and overloaded by extensions.
|
||||
* (See <a href="https://github.com/mar10/fancytree/wiki/TutorialExtensions">writing extensions</a>.)
|
||||
*
|
||||
* @see [writing extensions](https://github.com/mar10/fancytree/wiki/TutorialExtensions)
|
||||
* @mixin Fancytree_Hooks
|
||||
*/
|
||||
$.extend(
|
||||
@@ -6005,6 +6054,7 @@ var uniqueId = $.fn.extend( {
|
||||
* Call this method to create new nodes, or after the strucuture
|
||||
* was changed (e.g. after moving this node or adding/removing children)
|
||||
* nodeRenderTitle() and nodeRenderStatus() are implied.
|
||||
*
|
||||
* ```html
|
||||
* <li id='KEY' ftnode=NODE>
|
||||
* <span class='fancytree-node fancytree-expanded fancytree-has-children fancytree-lastsib fancytree-exp-el fancytree-ico-e'>
|
||||
@@ -7493,14 +7543,28 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
|
||||
/**
|
||||
* The plugin (derrived from <a href=" http://api.jqueryui.com/jQuery.widget/">jQuery.Widget</a>).<br>
|
||||
* This constructor is not called directly. Use `$(selector).fancytree({})`
|
||||
* to initialize the plugin instead.<br>
|
||||
* <pre class="sh_javascript sunlight-highlight-javascript">// Access widget methods and members:
|
||||
* var tree = $("#tree").fancytree("getTree");
|
||||
* var node = $("#tree").fancytree("getActiveNode", "1234");
|
||||
* </pre>
|
||||
* The plugin (derrived from [jQuery.Widget](http://api.jqueryui.com/jQuery.widget/)).
|
||||
*
|
||||
* **Note:**
|
||||
* These methods implement the standard jQuery UI widget API.
|
||||
* It is recommended to use methods of the {Fancytree} instance instead
|
||||
*
|
||||
* @example
|
||||
* // DEPRECATED: Access jQuery UI widget methods and members:
|
||||
* var tree = $("#tree").fancytree("getTree", "#myTree");
|
||||
* var node = $.ui.fancytree.getTree("#tree").getActiveNode();
|
||||
*
|
||||
* // RECOMMENDED: Use the Fancytree object API
|
||||
* var tree = $.ui.fancytree.getTree("#myTree");
|
||||
* var node = tree.getActiveNode();
|
||||
*
|
||||
* // or you may already have stored the tree instance upon creation:
|
||||
* import {createTree, version} from 'jquery.fancytree'
|
||||
* const tree = createTree('#tree', { ... });
|
||||
* var node = tree.getActiveNode();
|
||||
*
|
||||
* @see {Fancytree_Static#getTree}
|
||||
* @deprecated Use methods of the {Fancytree} instance instead
|
||||
* @mixin Fancytree_Widget
|
||||
*/
|
||||
|
||||
@@ -7584,6 +7648,17 @@ var uniqueId = $.fn.extend( {
|
||||
lazyLoad: null,
|
||||
postProcess: null,
|
||||
},
|
||||
_deprecationWarning: function(name) {
|
||||
var tree = this.tree;
|
||||
|
||||
if (tree && tree.options.debugLevel >= 3) {
|
||||
tree.warn(
|
||||
"$().fancytree('" +
|
||||
name +
|
||||
"') is deprecated (see https://wwwendt.de/tech/fancytree/doc/jsdoc/Fancytree_Widget.html"
|
||||
);
|
||||
}
|
||||
},
|
||||
/* Set up the widget, Called on first $().fancytree() */
|
||||
_create: function() {
|
||||
this.tree = new Fancytree(this);
|
||||
@@ -7701,11 +7776,11 @@ var uniqueId = $.fn.extend( {
|
||||
},
|
||||
|
||||
/** Use the destroy method to clean up any modifications your widget has made to the DOM */
|
||||
destroy: function() {
|
||||
_destroy: function() {
|
||||
this._unbind();
|
||||
this.tree._callHook("treeDestroy", this.tree);
|
||||
// In jQuery UI 1.8, you must invoke the destroy method from the base widget
|
||||
$.Widget.prototype.destroy.call(this);
|
||||
// $.Widget.prototype.destroy.call(this);
|
||||
// TODO: delete tree and nodes to make garbage collect easier?
|
||||
// TODO: In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method
|
||||
},
|
||||
@@ -7898,27 +7973,35 @@ var uniqueId = $.fn.extend( {
|
||||
},
|
||||
/** Return the active node or null.
|
||||
* @returns {FancytreeNode}
|
||||
* @deprecated Use methods of the Fancytree instance instead (<a href="Fancytree_Widget.html">example above</a>).
|
||||
*/
|
||||
getActiveNode: function() {
|
||||
this._deprecationWarning("getActiveNode");
|
||||
return this.tree.activeNode;
|
||||
},
|
||||
/** Return the matching node or null.
|
||||
* @param {string} key
|
||||
* @returns {FancytreeNode}
|
||||
* @deprecated Use methods of the Fancytree instance instead (<a href="Fancytree_Widget.html">example above</a>).
|
||||
*/
|
||||
getNodeByKey: function(key) {
|
||||
this._deprecationWarning("getNodeByKey");
|
||||
return this.tree.getNodeByKey(key);
|
||||
},
|
||||
/** Return the invisible system root node.
|
||||
* @returns {FancytreeNode}
|
||||
* @deprecated Use methods of the Fancytree instance instead (<a href="Fancytree_Widget.html">example above</a>).
|
||||
*/
|
||||
getRootNode: function() {
|
||||
this._deprecationWarning("getRootNode");
|
||||
return this.tree.rootNode;
|
||||
},
|
||||
/** Return the current tree instance.
|
||||
* @returns {Fancytree}
|
||||
* @deprecated Use `$.ui.fancytree.getTree()` instead (<a href="Fancytree_Widget.html">example above</a>).
|
||||
*/
|
||||
getTree: function() {
|
||||
this._deprecationWarning("getTree");
|
||||
return this.tree;
|
||||
},
|
||||
}
|
||||
@@ -7928,12 +8011,14 @@ var uniqueId = $.fn.extend( {
|
||||
FT = $.ui.fancytree;
|
||||
|
||||
/**
|
||||
* Static members in the `$.ui.fancytree` namespace.<br>
|
||||
* <br>
|
||||
* <pre class="sh_javascript sunlight-highlight-javascript">// Access static members:
|
||||
* Static members in the `$.ui.fancytree` namespace.
|
||||
* This properties and methods can be accessed without instantiating a concrete
|
||||
* Fancytree instance.
|
||||
*
|
||||
* @example
|
||||
* // Access static members:
|
||||
* var node = $.ui.fancytree.getNode(element);
|
||||
* alert($.ui.fancytree.version);
|
||||
* </pre>
|
||||
*
|
||||
* @mixin Fancytree_Static
|
||||
*/
|
||||
@@ -7941,11 +8026,14 @@ var uniqueId = $.fn.extend( {
|
||||
$.ui.fancytree,
|
||||
/** @lends Fancytree_Static# */
|
||||
{
|
||||
/** @type {string} */
|
||||
version: "2.33.0", // Set to semver by 'grunt release'
|
||||
/** @type {string} */
|
||||
/** Version number `"MAJOR.MINOR.PATCH"`
|
||||
* @type {string} */
|
||||
version: "2.34.0", // Set to semver by 'grunt release'
|
||||
/** @type {string}
|
||||
* @description `"production" for release builds` */
|
||||
buildType: "production", // Set to 'production' by 'grunt build'
|
||||
/** @type {int} */
|
||||
/** @type {int}
|
||||
* @description 0: silent .. 5: verbose (default: 3 for release builds). */
|
||||
debugLevel: 3, // Set to 3 by 'grunt build'
|
||||
// Used by $.ui.fancytree.debug() and as default for tree.options.debugLevel
|
||||
|
||||
@@ -7954,9 +8042,15 @@ var uniqueId = $.fn.extend( {
|
||||
_extensions: {},
|
||||
// focusTree: null,
|
||||
|
||||
/** Expose class object as $.ui.fancytree._FancytreeClass */
|
||||
/** Expose class object as `$.ui.fancytree._FancytreeClass`.
|
||||
* Useful to extend `$.ui.fancytree._FancytreeClass.prototype`.
|
||||
* @type {Fancytree}
|
||||
*/
|
||||
_FancytreeClass: Fancytree,
|
||||
/** Expose class object as $.ui.fancytree._FancytreeNodeClass */
|
||||
/** Expose class object as $.ui.fancytree._FancytreeNodeClass
|
||||
* Useful to extend `$.ui.fancytree._FancytreeNodeClass.prototype`.
|
||||
* @type {FancytreeNode}
|
||||
*/
|
||||
_FancytreeNodeClass: FancytreeNode,
|
||||
/* Feature checks to provide backwards compatibility */
|
||||
jquerySupports: {
|
||||
@@ -7983,10 +8077,8 @@ var uniqueId = $.fn.extend( {
|
||||
* @since 2.25
|
||||
*/
|
||||
createTree: function(el, opts) {
|
||||
var tree = $(el)
|
||||
.fancytree(opts)
|
||||
.fancytree("getTree");
|
||||
return tree;
|
||||
var $tree = $(el).fancytree(opts);
|
||||
return FT.getTree($tree);
|
||||
},
|
||||
/** Return a function that executes *fn* at most every *timeout* ms.
|
||||
* @param {integer} timeout
|
||||
@@ -8191,11 +8283,17 @@ var uniqueId = $.fn.extend( {
|
||||
if (!el.length) {
|
||||
el = $(orgEl).eq(0); // el was a selector: use first match
|
||||
}
|
||||
} else if (
|
||||
el instanceof Element ||
|
||||
el instanceof HTMLDocument
|
||||
) {
|
||||
el = $(el);
|
||||
} else if (el instanceof $) {
|
||||
el = el.eq(0); // el was a jQuery object: use the first DOM element
|
||||
el = el.eq(0); // el was a jQuery object: use the first
|
||||
} else if (el.originalEvent !== undefined) {
|
||||
el = $(el.target); // el was an Event
|
||||
}
|
||||
// el is a jQuery object wit one element here
|
||||
el = el.closest(":ui-fancytree");
|
||||
widget = el.data("ui-fancytree") || el.data("fancytree"); // the latter is required by jQuery <= 1.8
|
||||
return widget ? widget.tree : null;
|
||||
@@ -8203,11 +8301,11 @@ var uniqueId = $.fn.extend( {
|
||||
/** Return an option value that has a default, but may be overridden by a
|
||||
* callback or a node instance attribute.
|
||||
*
|
||||
* Evaluation sequence:<br>
|
||||
* Evaluation sequence:
|
||||
*
|
||||
* If tree.options.<optionName> is a callback that returns something, use that.<br>
|
||||
* Else if node.<optionName> is defined, use that.<br>
|
||||
* Else if tree.options.<optionName> is a value, use that.<br>
|
||||
* If `tree.options.<optionName>` is a callback that returns something, use that.
|
||||
* Else if `node.<optionName>` is defined, use that.
|
||||
* Else if `tree.options.<optionName>` is a value, use that.
|
||||
* Else use `defaultValue`.
|
||||
*
|
||||
* @param {string} optionName name of the option property (on node and tree)
|
||||
@@ -8565,8 +8663,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
// To keep the global namespace clean, we wrap everything in a closure.
|
||||
@@ -8602,7 +8700,7 @@ var uniqueId = $.fn.extend( {
|
||||
// New member functions can be added to the `Fancytree` class.
|
||||
// This function will be available for every tree instance:
|
||||
//
|
||||
// var tree = $("#tree").fancytree("getTree");
|
||||
// var tree = $.ui.fancytree.getTree("#tree");
|
||||
// tree.countSelected(false);
|
||||
|
||||
$.ui.fancytree._FancytreeClass.prototype.countSelected = function(topOnly) {
|
||||
@@ -8685,7 +8783,7 @@ var uniqueId = $.fn.extend( {
|
||||
// Every extension must be registered by a unique name.
|
||||
name: "childcounter",
|
||||
// Version information should be compliant with [semver](http://semver.org)
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
|
||||
// Extension specific options and their defaults.
|
||||
// This options will be available as `tree.options.childcounter.hideExpanded`
|
||||
@@ -8796,8 +8894,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -9155,7 +9253,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "clones",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
highlightActiveClones: true, // set 'fancytree-active-clone' on active clones and all peers
|
||||
@@ -9317,8 +9415,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -10322,7 +10420,7 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "dnd5",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autoExpandMS: 1500, // Expand nodes after n milliseconds of hovering
|
||||
@@ -10455,8 +10553,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -10748,7 +10846,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "edit",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
adjustWidthOfs: 4, // null: don't adjust input size to content
|
||||
@@ -10859,8 +10957,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11198,7 +11296,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "filter",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autoApply: true, // Re-apply last filter if lazy data is loaded
|
||||
@@ -11318,8 +11416,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11502,7 +11600,7 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "glyph",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
preset: null, // 'awesome3', 'awesome4', 'bootstrap3', 'material'
|
||||
@@ -11656,8 +11754,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11774,7 +11872,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "gridnav",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
autofocusInput: false, // Focus first embedded input if node gets activated
|
||||
@@ -11881,8 +11979,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -11911,7 +12009,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "multi",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
allowNoSelect: false, //
|
||||
@@ -12013,8 +12111,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -12154,7 +12252,7 @@ var uniqueId = $.fn.extend( {
|
||||
/**
|
||||
* [ext-persist] Remove persistence data of the given type(s).
|
||||
* Called like
|
||||
* $("#tree").fancytree("getTree").clearCookies("active expanded focus selected");
|
||||
* $.ui.fancytree.getTree("#tree").clearCookies("active expanded focus selected");
|
||||
*
|
||||
* @alias Fancytree#clearPersistData
|
||||
* @requires jquery.fancytree.persist.js
|
||||
@@ -12191,7 +12289,7 @@ var uniqueId = $.fn.extend( {
|
||||
* [ext-persist] Return persistence information from cookies
|
||||
*
|
||||
* Called like
|
||||
* $("#tree").fancytree("getTree").getPersistData();
|
||||
* $.ui.fancytree.getTree("#tree").getPersistData();
|
||||
*
|
||||
* @alias Fancytree#getPersistData
|
||||
* @requires jquery.fancytree.persist.js
|
||||
@@ -12214,7 +12312,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "persist",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
cookieDelimiter: "~",
|
||||
@@ -12507,8 +12605,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -12591,7 +12689,7 @@ var uniqueId = $.fn.extend( {
|
||||
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "table",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
checkboxColumnIdx: null, // render the checkboxes into the this column index (default: nodeColumnIdx)
|
||||
@@ -13057,8 +13155,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -13081,7 +13179,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "themeroller",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
activeClass: "ui-state-active", // Class added to active node
|
||||
@@ -13177,8 +13275,8 @@ var uniqueId = $.fn.extend( {
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
*/
|
||||
|
||||
(function(factory) {
|
||||
@@ -13308,7 +13406,7 @@ var uniqueId = $.fn.extend( {
|
||||
*/
|
||||
$.ui.fancytree.registerExtension({
|
||||
name: "wide",
|
||||
version: "2.33.0",
|
||||
version: "2.34.0",
|
||||
// Default options for this extension.
|
||||
options: {
|
||||
iconWidth: null, // Adjust this if @fancy-icon-width != "16px"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,8 +13,8 @@
|
||||
* Released under the MIT license
|
||||
* https://github.com/mar10/fancytree/wiki/LicenseInfo
|
||||
*
|
||||
* @version 2.33.0
|
||||
* @date 2019-10-29T08:00:07Z
|
||||
* @version 2.34.0
|
||||
* @date 2019-12-26T14:16:19Z
|
||||
******************************************************************************/
|
||||
/*------------------------------------------------------------------------------
|
||||
* Helpers
|
||||
|
||||
3
libraries/split.min.js
vendored
Normal file
3
libraries/split.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
5146
package-lock.json
generated
5146
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
54
package.json
54
package.json
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.37.5",
|
||||
"version": "0.40.5",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -21,40 +21,40 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"async-mutex": "0.1.4",
|
||||
"axios": "0.19.0",
|
||||
"axios": "0.19.1",
|
||||
"body-parser": "1.19.0",
|
||||
"cls-hooked": "4.2.2",
|
||||
"commonmark": "0.29.0",
|
||||
"commonmark": "0.29.1",
|
||||
"cookie-parser": "1.4.4",
|
||||
"csurf": "1.10.0",
|
||||
"dayjs": "1.8.17",
|
||||
"dayjs": "1.8.19",
|
||||
"debug": "4.1.1",
|
||||
"ejs": "2.7.1",
|
||||
"ejs": "2.7.4",
|
||||
"electron-debug": "3.0.1",
|
||||
"electron-dl": "1.14.0",
|
||||
"electron-dl": "2.0.0",
|
||||
"electron-find": "1.0.6",
|
||||
"electron-spellchecker": "2.2.0",
|
||||
"electron-spellchecker": "2.2.1",
|
||||
"electron-window-state": "5.0.3",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.0",
|
||||
"file-type": "12.4.0",
|
||||
"file-type": "13.0.3",
|
||||
"fs-extra": "8.1.0",
|
||||
"helmet": "3.21.2",
|
||||
"html": "1.0.0",
|
||||
"html2plaintext": "2.1.2",
|
||||
"http-proxy-agent": "2.1.0",
|
||||
"https-proxy-agent": "3.0.1",
|
||||
"http-proxy-agent": "3.0.0",
|
||||
"https-proxy-agent": "4.0.0",
|
||||
"image-type": "4.1.0",
|
||||
"imagemin": "7.0.0",
|
||||
"imagemin": "7.0.1",
|
||||
"imagemin-giflossy": "5.1.10",
|
||||
"imagemin-mozjpeg": "8.0.0",
|
||||
"imagemin-pngquant": "8.0.0",
|
||||
"ini": "1.3.5",
|
||||
"jimp": "0.8.5",
|
||||
"mime-types": "2.1.24",
|
||||
"jimp": "0.9.3",
|
||||
"mime-types": "2.1.26",
|
||||
"moment": "2.24.0",
|
||||
"multer": "1.4.2",
|
||||
"node-abi": "2.12.0",
|
||||
"node-abi": "2.13.0",
|
||||
"open": "7.0.0",
|
||||
"pngjs": "3.4.0",
|
||||
"portscanner": "2.2.0",
|
||||
@@ -63,34 +63,28 @@
|
||||
"rimraf": "3.0.0",
|
||||
"sanitize-filename": "1.6.3",
|
||||
"sax": "1.2.4",
|
||||
"semver": "6.3.0",
|
||||
"semver": "7.1.1",
|
||||
"serve-favicon": "2.5.0",
|
||||
"session-file-store": "1.3.1",
|
||||
"simple-node-logger": "18.12.23",
|
||||
"sqlite": "3.0.3",
|
||||
"sqlite3": "4.1.0",
|
||||
"string-similarity": "3.0.0",
|
||||
"sqlite3": "4.1.1",
|
||||
"string-similarity": "4.0.1",
|
||||
"tar-stream": "2.1.0",
|
||||
"turndown": "5.0.3",
|
||||
"turndown-plugin-gfm": "1.0.2",
|
||||
"unescape": "1.0.1",
|
||||
"ws": "7.2.0"
|
||||
"ws": "7.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "6.0.12",
|
||||
"electron-builder": "22.1.0",
|
||||
"electron-compile": "6.4.4",
|
||||
"electron-installer-debian": "2.0.1",
|
||||
"electron-packager": "14.1.0",
|
||||
"electron-rebuild": "1.8.6",
|
||||
"electron-builder": "21.2.0",
|
||||
"electron-packager": "14.1.1",
|
||||
"electron-rebuild": "1.8.8",
|
||||
"jsdoc": "3.6.3",
|
||||
"lorem-ipsum": "2.0.3",
|
||||
"xo": "0.25.3"
|
||||
"lorem-ipsum": "2.0.3"
|
||||
},
|
||||
"xo": {
|
||||
"envs": [
|
||||
"node",
|
||||
"browser"
|
||||
]
|
||||
"optionalDependencies": {
|
||||
"electron-installer-debian": "2.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ const sql = require('../services/sql');
|
||||
* @property {int} position
|
||||
* @property {boolean} isInheritable
|
||||
* @property {boolean} isDeleted
|
||||
* @property {string|null} deleteId - ID identifying delete transaction
|
||||
* @property {string} utcDateCreated
|
||||
* @property {string} utcDateModified
|
||||
*
|
||||
@@ -79,6 +80,10 @@ class Attribute extends Entity {
|
||||
|
||||
async beforeSaving() {
|
||||
if (!this.value) {
|
||||
if (this.type === 'relation') {
|
||||
throw new Error(`Cannot save relation ${this.name} since it does not target any note.`);
|
||||
}
|
||||
|
||||
// null value isn't allowed
|
||||
this.value = "";
|
||||
}
|
||||
@@ -109,6 +114,7 @@ class Attribute extends Entity {
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.isOwned;
|
||||
delete pojo.__note;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ const sql = require('../services/sql');
|
||||
* @property {string} prefix
|
||||
* @property {boolean} isExpanded
|
||||
* @property {boolean} isDeleted
|
||||
* @property {string|null} deleteId - ID identifying delete transaction
|
||||
* @property {string} utcDateModified
|
||||
* @property {string} utcDateCreated
|
||||
*
|
||||
@@ -25,7 +26,7 @@ class Branch extends Entity {
|
||||
static get entityName() { return "branches"; }
|
||||
static get primaryKeyName() { return "branchId"; }
|
||||
// notePosition is not part of hash because it would produce a lot of updates in case of reordering
|
||||
static get hashedProperties() { return ["branchId", "noteId", "parentNoteId", "isDeleted", "prefix"]; }
|
||||
static get hashedProperties() { return ["branchId", "noteId", "parentNoteId", "isDeleted", "deleteId", "prefix"]; }
|
||||
|
||||
constructor(row = {}) {
|
||||
super(row);
|
||||
|
||||
@@ -24,6 +24,7 @@ const RELATION_DEFINITION = 'relation-definition';
|
||||
* @property {int} contentLength - length of content
|
||||
* @property {boolean} isProtected - true if note is protected
|
||||
* @property {boolean} isDeleted - true if note is deleted
|
||||
* @property {string|null} deleteId - ID identifying delete transaction
|
||||
* @property {boolean} isErased - true if note's content is erased after it has been deleted
|
||||
* @property {string} dateCreated - local date time (with offset)
|
||||
* @property {string} dateModified - local date time (with offset)
|
||||
@@ -35,7 +36,7 @@ const RELATION_DEFINITION = 'relation-definition';
|
||||
class Note extends Entity {
|
||||
static get entityName() { return "notes"; }
|
||||
static get primaryKeyName() { return "noteId"; }
|
||||
static get hashedProperties() { return ["noteId", "title", "type", "isProtected", "isDeleted"]; }
|
||||
static get hashedProperties() { return ["noteId", "title", "type", "isProtected", "isDeleted", "deleteId"]; }
|
||||
|
||||
/**
|
||||
* @param row - object containing database row from "notes" table
|
||||
@@ -109,14 +110,24 @@ class Note extends Entity {
|
||||
async getJsonContent() {
|
||||
const content = await this.getContent();
|
||||
|
||||
if (!content || !content.trim()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(content);
|
||||
}
|
||||
|
||||
/** @returns {Promise} */
|
||||
async setContent(content) {
|
||||
if (content === null || content === undefined) {
|
||||
throw new Error(`Cannot set null content to note ${this.noteId}`);
|
||||
}
|
||||
|
||||
content = Buffer.isBuffer(content) ? content : Buffer.from(content);
|
||||
|
||||
// force updating note itself so that dateModified is represented correctly even for the content
|
||||
this.forcedChange = true;
|
||||
this.contentLength = content.length;
|
||||
this.contentLength = content.byteLength;
|
||||
await this.save();
|
||||
|
||||
this.content = content;
|
||||
@@ -125,7 +136,7 @@ class Note extends Entity {
|
||||
noteId: this.noteId,
|
||||
content: content,
|
||||
utcDateModified: dateUtils.utcNowDateTime(),
|
||||
hash: utils.hash(this.noteId + "|" + content)
|
||||
hash: utils.hash(this.noteId + "|" + content.toString())
|
||||
};
|
||||
|
||||
if (this.isProtected) {
|
||||
@@ -192,26 +203,36 @@ class Note extends Entity {
|
||||
return null;
|
||||
}
|
||||
|
||||
async loadOwnedAttributesToCache() {
|
||||
this.__ownedAttributeCache = await repository.getEntities(`SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`, [this.noteId]);
|
||||
return this.__ownedAttributeCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Attribute[]>} attributes belonging to this specific note (excludes inherited attributes)
|
||||
* This method is a faster variant of getAttributes() which looks for only owned attributes.
|
||||
* Use when inheritance is not needed and/or in batch/performance sensitive operations.
|
||||
*
|
||||
* This method can be significantly faster than the getAttributes()
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} note's "owned" attributes - excluding inherited ones
|
||||
*/
|
||||
async getOwnedAttributes(type, name) {
|
||||
let query = `SELECT * FROM attributes WHERE isDeleted = 0 AND noteId = ?`;
|
||||
const params = [this.noteId];
|
||||
|
||||
if (type) {
|
||||
query += ` AND type = ?`;
|
||||
params.push(type);
|
||||
if (!this.__ownedAttributeCache) {
|
||||
await this.loadOwnedAttributesToCache();
|
||||
}
|
||||
|
||||
if (name) {
|
||||
query += ` AND name = ?`;
|
||||
params.push(name);
|
||||
if (type && name) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__ownedAttributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.__ownedAttributeCache.slice();
|
||||
}
|
||||
|
||||
return await repository.getEntities(query, params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -233,19 +254,26 @@ class Note extends Entity {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
async getAttributes(type, name) {
|
||||
if (!this.__attributeCache) {
|
||||
await this.loadAttributesToCache();
|
||||
}
|
||||
|
||||
if (name) {
|
||||
if (type && name) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.__attributeCache;
|
||||
return this.__attributeCache.slice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +282,15 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
return await this.getAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - label name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), excluding inherited ones
|
||||
*/
|
||||
async getOwnedLabels(name) {
|
||||
return await this.getOwnedAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +298,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
return await this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,7 +306,15 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
return await this.getAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - relation name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), excluding inherited ones
|
||||
*/
|
||||
async getOwnedRelations(name) {
|
||||
return await this.getOwnedAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,7 +337,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
return await this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,6 +346,7 @@ class Note extends Entity {
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.__attributeCache = null;
|
||||
this.__ownedAttributeCache = null;
|
||||
}
|
||||
|
||||
/** @returns {Promise<void>} */
|
||||
@@ -311,11 +356,10 @@ class Note extends Entity {
|
||||
tree(noteId, level) AS (
|
||||
SELECT ?, 0
|
||||
UNION
|
||||
SELECT branches.parentNoteId, tree.level + 1 FROM branches
|
||||
SELECT branches.parentNoteId, tree.level + 1
|
||||
FROM branches
|
||||
JOIN tree ON branches.noteId = tree.noteId
|
||||
JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
WHERE notes.isDeleted = 0
|
||||
AND branches.isDeleted = 0
|
||||
WHERE branches.isDeleted = 0
|
||||
),
|
||||
treeWithAttrs(noteId, level) AS (
|
||||
SELECT * FROM tree
|
||||
@@ -334,6 +378,11 @@ class Note extends Entity {
|
||||
// we order by noteId so that attributes from same note stay together. Actual noteId ordering doesn't matter.
|
||||
|
||||
const filteredAttributes = attributes.filter((attr, index) => {
|
||||
// if this exact attribute already appears then don't include it (can happen via cloning)
|
||||
if (attributes.findIndex(it => it.attributeId === attr.attributeId) !== index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr.isDefinition()) {
|
||||
const firstDefinitionIndex = attributes.findIndex(el => el.type === attr.type && el.name === attr.name);
|
||||
|
||||
@@ -377,6 +426,15 @@ class Note extends Entity {
|
||||
return !!await this.getAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<boolean>} true if note has an attribute with given type and name (excluding inherited)
|
||||
*/
|
||||
async hasOwnedAttribute(type, name) {
|
||||
return !!await this.getOwnedAttribute(type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
@@ -391,7 +449,7 @@ class Note extends Entity {
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
|
||||
* @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getAttributeValue(type, name) {
|
||||
const attr = await this.getAttribute(type, name);
|
||||
@@ -399,6 +457,17 @@ class Note extends Entity {
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} type - attribute type (label, relation, etc.)
|
||||
* @param {string} name - attribute name
|
||||
* @returns {Promise<string|null>} attribute value of given type and name or null if no such attribute exists.
|
||||
*/
|
||||
async getOwnedAttributeValue(type, name) {
|
||||
const attr = await this.getOwnedAttribute(type, name);
|
||||
|
||||
return attr ? attr.value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, attribute is either set or removed.
|
||||
*
|
||||
@@ -426,7 +495,7 @@ class Note extends Entity {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async setAttribute(type, name, value) {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
const attributes = await this.loadOwnedAttributesToCache();
|
||||
let attr = attributes.find(attr => attr.type === type && attr.name === name);
|
||||
|
||||
if (attr) {
|
||||
@@ -460,10 +529,10 @@ class Note extends Entity {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async removeAttribute(type, name, value) {
|
||||
const attributes = await this.getOwnedAttributes();
|
||||
const attributes = await this.loadOwnedAttributesToCache();
|
||||
|
||||
for (const attribute of attributes) {
|
||||
if (attribute.type === type && (value === undefined || value === attribute.value)) {
|
||||
if (attribute.type === type && attribute.name === name && (value === undefined || value === attribute.value)) {
|
||||
attribute.isDeleted = true;
|
||||
await attribute.save();
|
||||
|
||||
@@ -472,42 +541,104 @@ class Note extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<Attribute>}
|
||||
*/
|
||||
async addAttribute(type, name, value = "") {
|
||||
const attr = new Attribute({
|
||||
noteId: this.noteId,
|
||||
type: type,
|
||||
name: name,
|
||||
value: value
|
||||
});
|
||||
|
||||
await attr.save();
|
||||
|
||||
this.invalidateAttributeCache();
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
async addLabel(name, value = "") {
|
||||
return await this.addAttribute(LABEL, name, value);
|
||||
}
|
||||
|
||||
async addRelation(name, targetNoteId) {
|
||||
return await this.addAttribute(RELATION, name, targetNoteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (including inherited)
|
||||
*/
|
||||
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<boolean>} true if label exists (excluding inherited)
|
||||
*/
|
||||
async hasOwnedLabel(name) { return await this.hasOwnedAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (including inherited)
|
||||
*/
|
||||
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<boolean>} true if relation exists (excluding inherited)
|
||||
*/
|
||||
async hasOwnedRelation(name) { return await this.hasOwnedAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute>} label if it exists, null otherwise
|
||||
* @returns {Promise<Attribute|null>} label if it exists, null otherwise
|
||||
*/
|
||||
async getLabel(name) { return await this.getAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<Attribute|null>} label if it exists, null otherwise
|
||||
*/
|
||||
async getOwnedLabel(name) { return await this.getOwnedAttribute(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute>} relation if it exists, null otherwise
|
||||
* @returns {Promise<Attribute|null>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getRelation(name) { return await this.getAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<Attribute|null>} relation if it exists, null otherwise
|
||||
*/
|
||||
async getOwnedRelation(name) { return await this.getOwnedAttribute(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string>} label value if label exists, null otherwise
|
||||
* @returns {Promise<string|null>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - label name
|
||||
* @returns {Promise<string|null>} label value if label exists, null otherwise
|
||||
*/
|
||||
async getOwnedLabelValue(name) { return await this.getOwnedAttributeValue(LABEL, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string>} relation value if relation exists, null otherwise
|
||||
* @returns {Promise<string|null>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name - relation name
|
||||
* @returns {Promise<string|null>} relation value if relation exists, null otherwise
|
||||
*/
|
||||
async getOwnedRelationValue(name) { return await this.getOwnedAttributeValue(RELATION, name); }
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
@@ -518,6 +649,16 @@ class Note extends Entity {
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
|
||||
*/
|
||||
async getOwnedRelationTarget(name) {
|
||||
const relation = await this.getOwnedRelation(name);
|
||||
|
||||
return relation ? await repository.getNote(relation.value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on enabled, label is either set or removed.
|
||||
*
|
||||
@@ -670,8 +811,10 @@ class Note extends Entity {
|
||||
FROM attributes
|
||||
WHERE noteId = ? AND
|
||||
isDeleted = 0 AND
|
||||
type = 'relation' AND
|
||||
name IN ('internal-link', 'image-link', 'relation-map-link')`, [this.noteId]);
|
||||
((type = 'relation' AND
|
||||
name IN ('internalLink', 'imageLink', 'relationMapLink', 'includeNoteLink'))
|
||||
OR
|
||||
(type = 'label' AND name = 'externalLink'))`, [this.noteId]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -748,6 +891,16 @@ class Note extends Entity {
|
||||
return notePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ancestorNoteId
|
||||
* @return {Promise<boolean>} - true if ancestorNoteId occurs in at least one of the note's paths
|
||||
*/
|
||||
async isDescendantOfNote(ancestorNoteId) {
|
||||
const notePaths = await this.getAllNotePaths();
|
||||
|
||||
return notePaths.some(path => path.includes(ancestorNoteId));
|
||||
}
|
||||
|
||||
beforeSaving() {
|
||||
if (!this.isDeleted) {
|
||||
this.isDeleted = false;
|
||||
@@ -787,7 +940,9 @@ class Note extends Entity {
|
||||
|
||||
delete pojo.isContentAvailable;
|
||||
delete pojo.__attributeCache;
|
||||
delete pojo.__ownedAttributeCache;
|
||||
delete pojo.content;
|
||||
/** zero references to contentHash, probably can be removed */
|
||||
delete pojo.contentHash;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ import cssLoader from './services/css_loader.js';
|
||||
import dateNoteService from './services/date_notes.js';
|
||||
import sidebarService from './services/sidebar.js';
|
||||
import importService from './services/import.js';
|
||||
import keyboardActionService from "./services/keyboard_actions.js";
|
||||
import splitService from "./services/split.js";
|
||||
import optionService from "./services/options.js";
|
||||
import noteContentRenderer from "./services/note_content_renderer.js";
|
||||
|
||||
window.glob.isDesktop = utils.isDesktop;
|
||||
window.glob.isMobile = utils.isMobile;
|
||||
@@ -38,6 +42,20 @@ window.glob.isMobile = utils.isMobile;
|
||||
window.glob.getActiveNode = treeService.getActiveNode;
|
||||
window.glob.getHeaders = server.getHeaders;
|
||||
window.glob.showAddLinkDialog = () => import('./dialogs/add_link.js').then(d => d.showDialog());
|
||||
window.glob.showIncludeNoteDialog = cb => import('./dialogs/include_note.js').then(d => d.showDialog(cb));
|
||||
window.glob.loadIncludedNote = async (noteId, el) => {
|
||||
const note = await treeCache.getNote(noteId);
|
||||
|
||||
if (note) {
|
||||
$(el).empty().append($("<h3>").append(await linkService.createNoteLink(note.noteId, {
|
||||
showTooltip: false
|
||||
})));
|
||||
|
||||
const {renderedContent} = await noteContentRenderer.getRenderedContent(note);
|
||||
|
||||
$(el).append(renderedContent);
|
||||
}
|
||||
};
|
||||
// this is required by CKEditor when uploading images
|
||||
window.glob.noteChanged = noteDetailService.noteChanged;
|
||||
window.glob.refreshTree = treeService.reload;
|
||||
@@ -78,7 +96,7 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
|
||||
};
|
||||
|
||||
for (const appCssNoteId of window.appCssNoteIds) {
|
||||
cssLoader.requireCss(`/api/notes/download/${appCssNoteId}`);
|
||||
cssLoader.requireCss(`api/notes/download/${appCssNoteId}`);
|
||||
}
|
||||
|
||||
const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/";
|
||||
@@ -108,18 +126,8 @@ $("body").on("click", "a.external", function () {
|
||||
});
|
||||
|
||||
if (utils.isElectron()) {
|
||||
require('electron').ipcRenderer.on('create-day-sub-note', async function(event) {
|
||||
const todayNote = await dateNoteService.getTodayNote();
|
||||
const notePath = await treeService.getSomeNotePath(todayNote);
|
||||
|
||||
const node = await treeService.expandToNote(notePath);
|
||||
|
||||
await noteDetailService.openEmptyTab(false);
|
||||
|
||||
await treeService.createNote(node, todayNote.noteId, 'into', {
|
||||
type: "text",
|
||||
isProtected: node.data.isProtected
|
||||
});
|
||||
require('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) {
|
||||
keyboardActionService.triggerAction(actionName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -136,7 +144,7 @@ $noteTabContainer.on("click", ".export-note-button", function () {
|
||||
$noteTabContainer.on("click", ".import-files-button",
|
||||
() => import('./dialogs/import.js').then(d => d.showDialog(treeService.getActiveNode())));
|
||||
|
||||
$noteTabContainer.on("click", ".print-note-button", async function () {
|
||||
async function printActiveNote() {
|
||||
if ($(this).hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
@@ -151,10 +159,23 @@ $noteTabContainer.on("click", ".print-note-button", async function () {
|
||||
$tabContext.$tabContent.find('.note-detail-component:visible').printThis({
|
||||
header: $("<h2>").text($tabContext.note && $tabContext.note.title).prop('outerHTML') ,
|
||||
importCSS: false,
|
||||
loadCSS: "libraries/codemirror/codemirror.css",
|
||||
loadCSS: [
|
||||
"libraries/codemirror/codemirror.css",
|
||||
"libraries/ckeditor/ckeditor-content.css",
|
||||
"libraries/ckeditor/ckeditor-content.css",
|
||||
"libraries/bootstrap/css/bootstrap.min.css",
|
||||
"stylesheets/print.css",
|
||||
"stylesheets/relation_map.css",
|
||||
"stylesheets/themes.css",
|
||||
"stylesheets/detail.css"
|
||||
],
|
||||
debug: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("PrintActiveNote", printActiveNote);
|
||||
|
||||
$noteTabContainer.on("click", ".print-note-button", printActiveNote);
|
||||
|
||||
$('[data-toggle="tooltip"]').tooltip({
|
||||
html: true
|
||||
@@ -181,4 +202,34 @@ noteAutocompleteService.init();
|
||||
|
||||
if (utils.isElectron()) {
|
||||
import("./services/spell_check.js").then(spellCheckService => spellCheckService.initSpellCheck());
|
||||
}
|
||||
}
|
||||
|
||||
optionService.waitForOptions().then(options => {
|
||||
if (utils.isElectron() && !options.is('nativeTitleBarVisible')) {
|
||||
$("#title-bar-buttons").show();
|
||||
|
||||
$("#minimize-btn").on('click', () => {
|
||||
$("#minimize-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
remote.BrowserWindow.getFocusedWindow().minimize();
|
||||
});
|
||||
|
||||
$("#maximize-btn").on('click', () => {
|
||||
$("#maximize-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
const focusedWindow = remote.BrowserWindow.getFocusedWindow();
|
||||
|
||||
if (focusedWindow.isMaximized()) {
|
||||
focusedWindow.unmaximize();
|
||||
} else {
|
||||
focusedWindow.maximize();
|
||||
}
|
||||
});
|
||||
|
||||
$("#close-btn").on('click', () => {
|
||||
$("#close-btn").trigger('blur');
|
||||
const {remote} = require('electron');
|
||||
remote.BrowserWindow.getFocusedWindow().close();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -10,8 +10,6 @@ const $buildRevision = $("#build-revision");
|
||||
const $dataDirectory = $("#data-directory");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
const appInfo = await server.get('app-info');
|
||||
|
||||
$appVersion.text(appInfo.appVersion);
|
||||
@@ -22,7 +20,5 @@ export async function showDialog() {
|
||||
$buildRevision.attr('href', 'https://github.com/zadam/trilium/commit/' + appInfo.buildRevision);
|
||||
$dataDirectory.text(appInfo.dataDirectory);
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
@@ -11,13 +11,9 @@ const $linkTitle = $("#link-title");
|
||||
const $addLinkTitleFormGroup = $("#add-link-title-form-group");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
$addLinkTitleFormGroup.toggle(!hasSelection());
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
$autoComplete.val('').trigger('focus');
|
||||
$linkTitle.val('');
|
||||
|
||||
@@ -287,8 +287,6 @@ function initKoPlugins() {
|
||||
}
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
await libraryLoader.requireLibrary(libraryLoader.KNOCKOUT);
|
||||
|
||||
// lazily apply bindings on first use
|
||||
@@ -300,11 +298,9 @@ export async function showDialog() {
|
||||
ko.applyBindings(attributesModel, $dialog[0]);
|
||||
}
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
await attributesModel.loadAttributes();
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
|
||||
$dialog.on('focus', '.attribute-name', function (e) {
|
||||
|
||||
28
src/public/javascripts/dialogs/backend_log.js
Normal file
28
src/public/javascripts/dialogs/backend_log.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import server from "../services/server.js";
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const $dialog = $("#backend-log-dialog");
|
||||
const $backendLogTextArea = $("#backend-log-textarea");
|
||||
const $refreshBackendLog = $("#refresh-backend-log-button");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.openDialog($dialog);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
function scrollToBottom() {
|
||||
$backendLogTextArea.scrollTop($backendLogTextArea[0].scrollHeight);
|
||||
}
|
||||
|
||||
async function load() {
|
||||
const backendLog = await server.get('backend-log');
|
||||
|
||||
$backendLogTextArea.text(backendLog);
|
||||
|
||||
scrollToBottom();
|
||||
}
|
||||
|
||||
$refreshBackendLog.on('click', load);
|
||||
|
||||
$dialog.on('shown.bs.modal', scrollToBottom);
|
||||
@@ -13,15 +13,21 @@ const $noteTitle = $('#branch-prefix-note-title');
|
||||
let branchId;
|
||||
|
||||
export async function showDialog(node) {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
|
||||
branchId = node.data.branchId;
|
||||
const branch = treeCache.getBranch(branchId);
|
||||
|
||||
if (branch.noteId === 'root') {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentNote = await treeCache.getNote(branch.parentNoteId);
|
||||
|
||||
if (parentNote.type === 'search') {
|
||||
return;
|
||||
}
|
||||
|
||||
utils.openDialog($dialog);
|
||||
|
||||
$treePrefixInput.val(branch.prefix);
|
||||
|
||||
const noteTitle = await treeUtils.getNoteTitle(node.data.noteId);
|
||||
|
||||
@@ -22,11 +22,7 @@ export async function showDialog(noteIds) {
|
||||
}
|
||||
}
|
||||
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
$noteAutoComplete.val('').trigger('focus');
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ let taskId = '';
|
||||
let branchId = null;
|
||||
|
||||
export async function showDialog(node, defaultType) {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
// each opening of the dialog resets the taskId so we don't associate it with previous exports anymore
|
||||
taskId = '';
|
||||
$exportButton.removeAttr("disabled");
|
||||
@@ -38,9 +36,7 @@ export async function showDialog(node, defaultType) {
|
||||
|
||||
$("#opml-v2").prop("checked", true); // setting default
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
branchId = node.data.branchId;
|
||||
|
||||
|
||||
@@ -3,9 +3,5 @@ import utils from "../services/utils.js";
|
||||
const $dialog = $("#help-dialog");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
@@ -16,8 +16,6 @@ const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
|
||||
let parentNoteId = null;
|
||||
|
||||
export async function showDialog(node) {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
$fileUploadInput.val('').trigger('change'); // to trigger Import button disabling listener below
|
||||
|
||||
$safeImportCheckbox.prop("checked", true);
|
||||
@@ -26,13 +24,11 @@ export async function showDialog(node) {
|
||||
$codeImportedAsCodeCheckbox.prop("checked", true);
|
||||
$explodeArchivesCheckbox.prop("checked", true);
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
parentNoteId = node.data.noteId;
|
||||
|
||||
$noteTitle.text(await treeUtils.getNoteTitle(parentNoteId));
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
|
||||
$form.on('submit', () => {
|
||||
|
||||
36
src/public/javascripts/dialogs/include_note.js
Normal file
36
src/public/javascripts/dialogs/include_note.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import treeUtils from '../services/tree_utils.js';
|
||||
import noteAutocompleteService from '../services/note_autocomplete.js';
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const $dialog = $("#include-note-dialog");
|
||||
const $form = $("#include-note-form");
|
||||
const $autoComplete = $("#include-note-autocomplete");
|
||||
let callback = null;
|
||||
|
||||
export async function showDialog(cb) {
|
||||
callback = cb;
|
||||
|
||||
$autoComplete.val('');
|
||||
|
||||
utils.openDialog($dialog);
|
||||
|
||||
noteAutocompleteService.initNoteAutocomplete($autoComplete, { hideGoToSelectedNoteButton: true });
|
||||
noteAutocompleteService.showRecentNotes($autoComplete);
|
||||
}
|
||||
|
||||
$form.on('submit', () => {
|
||||
const notePath = $autoComplete.getSelectedPath();
|
||||
|
||||
if (notePath) {
|
||||
$dialog.modal('hide');
|
||||
|
||||
if (callback) {
|
||||
callback(treeUtils.getNoteIdFromNotePath(notePath));
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error("No noteId to include.");
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
@@ -10,13 +10,9 @@ let $originallyFocused; // element focused before the dialog was opened so we ca
|
||||
export function info(message) {
|
||||
$originallyFocused = $(':focus');
|
||||
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$infoContent.text(message);
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
return new Promise((res, rej) => { resolve = res; });
|
||||
}
|
||||
|
||||
@@ -8,13 +8,9 @@ const $autoComplete = $("#jump-to-note-autocomplete");
|
||||
const $showInFullTextButton = $("#show-in-full-text-button");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$autoComplete.val('');
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
noteAutocompleteService.initNoteAutocomplete($autoComplete, { hideGoToSelectedNoteButton: true })
|
||||
.on('autocomplete:selected', function(event, suggestion, dataset) {
|
||||
|
||||
@@ -16,10 +16,6 @@ function getOptions() {
|
||||
}
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
// set default settings
|
||||
$maxNotesInput.val(20);
|
||||
|
||||
@@ -27,7 +23,7 @@ export async function showDialog() {
|
||||
|
||||
$linkMapContainer.empty();
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
|
||||
$dialog.on('shown.bs.modal', () => {
|
||||
|
||||
@@ -26,6 +26,10 @@ async function convertMarkdownToHtml(text) {
|
||||
}
|
||||
|
||||
export async function importMarkdownInline() {
|
||||
if (noteDetailService.getActiveTabNoteType() !== 'text') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
const {clipboard} = require('electron');
|
||||
const text = clipboard.readText();
|
||||
@@ -33,9 +37,7 @@ export async function importMarkdownInline() {
|
||||
convertMarkdownToHtml(text);
|
||||
}
|
||||
else {
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import noteAutocompleteService from "../services/note_autocomplete.js";
|
||||
import utils from "../services/utils.js";
|
||||
import cloningService from "../services/cloning.js";
|
||||
import treeUtils from "../services/tree_utils.js";
|
||||
import toastService from "../services/toast.js";
|
||||
import treeCache from "../services/tree_cache.js";
|
||||
import treeChangesService from "../services/branches.js";
|
||||
@@ -18,11 +16,7 @@ let movedNodes;
|
||||
export async function showDialog(nodes) {
|
||||
movedNodes = nodes;
|
||||
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
$noteAutoComplete.val('').trigger('focus');
|
||||
|
||||
|
||||
@@ -10,11 +10,7 @@ const $mime = $("#note-info-mime");
|
||||
const $okButton = $("#note-info-ok-button");
|
||||
|
||||
export function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
const activeNote = noteDetailService.getActiveTabNote();
|
||||
|
||||
|
||||
@@ -29,11 +29,7 @@ export async function showCurrentNoteRevisions() {
|
||||
}
|
||||
|
||||
export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
await loadNoteRevisions(noteId, noteRevisionId);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,7 @@ const $dialog = $("#note-source-dialog");
|
||||
const $noteSource = $("#note-source");
|
||||
|
||||
export function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
const noteText = noteDetailService.getActiveTabNote().content;
|
||||
|
||||
|
||||
@@ -6,13 +6,9 @@ import utils from "../services/utils.js";
|
||||
const $dialog = $("#options-dialog");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
const options = await server.get('options');
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
(await Promise.all([
|
||||
import('./options/advanced.js'),
|
||||
@@ -22,6 +18,7 @@ export async function showDialog() {
|
||||
import('./options/other.js'),
|
||||
import('./options/sidebar.js'),
|
||||
import('./options/sync.js'),
|
||||
import('./options/keyboard_shortcuts.js'),
|
||||
]))
|
||||
.map(m => new m.default)
|
||||
.forEach(tab => {
|
||||
|
||||
@@ -3,19 +3,23 @@ import toastService from "../../services/toast.js";
|
||||
|
||||
const TPL = `
|
||||
<h4 style="margin-top: 0;">Sync</h4>
|
||||
<button id="force-full-sync-button" class="btn btn-secondary">Force full sync</button>
|
||||
<button id="force-full-sync-button" class="btn">Force full sync</button>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<button id="fill-sync-rows-button" class="btn btn-secondary">Fill sync rows</button>
|
||||
<button id="fill-sync-rows-button" class="btn">Fill sync rows</button>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<h4>Consistency checks</h4>
|
||||
|
||||
<button id="find-and-fix-consistency-issues-button" class="btn">Find and fix consistency issues</button><br/><br/>
|
||||
|
||||
<h4>Debugging</h4>
|
||||
|
||||
<button id="anonymize-button" class="btn btn-secondary">Save anonymized database</button><br/><br/>
|
||||
<button id="anonymize-button" class="btn">Save anonymized database</button><br/><br/>
|
||||
|
||||
<p>This action will create a new copy of the database and anonymise it (remove all note content and leave only structure and metadata)
|
||||
for sharing online for debugging purposes without fear of leaking your personal data.</p>
|
||||
@@ -24,7 +28,7 @@ const TPL = `
|
||||
|
||||
<p>This will rebuild database which will typically result in smaller database file. No data will be actually changed.</p>
|
||||
|
||||
<button id="vacuum-database-button" class="btn btn-secondary">Vacuum database</button>`;
|
||||
<button id="vacuum-database-button" class="btn">Vacuum database</button>`;
|
||||
|
||||
export default class AdvancedOptions {
|
||||
constructor() {
|
||||
@@ -33,9 +37,8 @@ export default class AdvancedOptions {
|
||||
this.$forceFullSyncButton = $("#force-full-sync-button");
|
||||
this.$fillSyncRowsButton = $("#fill-sync-rows-button");
|
||||
this.$anonymizeButton = $("#anonymize-button");
|
||||
this.$cleanupSoftDeletedButton = $("#cleanup-soft-deleted-items-button");
|
||||
this.$cleanupUnusedImagesButton = $("#cleanup-unused-images-button");
|
||||
this.$vacuumDatabaseButton = $("#vacuum-database-button");
|
||||
this.$findAndFixConsistencyIssuesButton = $("#find-and-fix-consistency-issues-button");
|
||||
|
||||
this.$forceFullSyncButton.on('click', async () => {
|
||||
await server.post('sync/force-full-sync');
|
||||
@@ -55,26 +58,16 @@ export default class AdvancedOptions {
|
||||
toastService.showMessage("Created anonymized database");
|
||||
});
|
||||
|
||||
this.$cleanupSoftDeletedButton.on('click', async () => {
|
||||
if (confirm("Do you really want to clean up soft-deleted items?")) {
|
||||
await server.post('cleanup/cleanup-soft-deleted-items');
|
||||
|
||||
toastService.showMessage("Soft deleted items have been cleaned up");
|
||||
}
|
||||
});
|
||||
|
||||
this.$cleanupUnusedImagesButton.on('click', async () => {
|
||||
if (confirm("Do you really want to clean up unused images?")) {
|
||||
await server.post('cleanup/cleanup-unused-images');
|
||||
|
||||
toastService.showMessage("Unused images have been cleaned up");
|
||||
}
|
||||
});
|
||||
|
||||
this.$vacuumDatabaseButton.on('click', async () => {
|
||||
await server.post('cleanup/vacuum-database');
|
||||
|
||||
toastService.showMessage("Database has been vacuumed");
|
||||
});
|
||||
|
||||
this.$findAndFixConsistencyIssuesButton.on('click', async () => {
|
||||
await server.post('cleanup/find-and-fix-consistency-issues');
|
||||
|
||||
toastService.showMessage("Consistency issues should be fixed.");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,13 @@ const TPL = `
|
||||
|
||||
<input type="number" class="form-control" id="zoom-factor-select" min="0.3" max="2.0" step="0.1"/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-4">
|
||||
<label for="one-tab-display-select">If there's only one tab, then...</label>
|
||||
<select class="form-control" id="one-tab-display-select">
|
||||
<option value="show">show the tab bar</option>
|
||||
<option value="hide">hide the tab bar</option>
|
||||
<label for="native-title-bar-select">Native title bar (requires app restart)</label>
|
||||
|
||||
<select class="form-control" id="native-title-bar-select">
|
||||
<option value="show">enabled</option>
|
||||
<option value="hide">disabled</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -69,37 +70,6 @@ const TPL = `
|
||||
</div>
|
||||
|
||||
<p>Note that tree and detail font sizing is relative to the main font size setting.</p>
|
||||
|
||||
<h4>Left pane sizing</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Left pane minimum width (in pixels)</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="left-pane-min-width" min="100" max="2000" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Left pane width percent of window size</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="left-pane-width-percent" min="0" max="99" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Left pane width is calculated from the percent of window size, if this is smaller than minimum width, then minimum width is used. If you want to have fixed width left pane, set minimum width to the desired width and set percent to 0.</p>
|
||||
|
||||
</form>`;
|
||||
|
||||
export default class ApperanceOptions {
|
||||
@@ -108,9 +78,7 @@ export default class ApperanceOptions {
|
||||
|
||||
this.$themeSelect = $("#theme-select");
|
||||
this.$zoomFactorSelect = $("#zoom-factor-select");
|
||||
this.$oneTabDisplaySelect = $("#one-tab-display-select");
|
||||
this.$leftPaneMinWidth = $("#left-pane-min-width");
|
||||
this.$leftPaneWidthPercent = $("#left-pane-width-percent");
|
||||
this.$nativeTitleBarSelect = $("#native-title-bar-select");
|
||||
this.$mainFontSize = $("#main-font-size");
|
||||
this.$treeFontSize = $("#tree-font-size");
|
||||
this.$detailFontSize = $("#detail-font-size");
|
||||
@@ -131,7 +99,7 @@ export default class ApperanceOptions {
|
||||
if (noteId) {
|
||||
// make sure the CSS is loaded
|
||||
// if the CSS has been loaded and then updated then the changes won't take effect though
|
||||
cssLoader.requireCss(`/api/notes/download/${noteId}`);
|
||||
cssLoader.requireCss(`api/notes/download/${noteId}`);
|
||||
}
|
||||
|
||||
this.$body.addClass("theme-" + newTheme);
|
||||
@@ -141,23 +109,10 @@ export default class ApperanceOptions {
|
||||
|
||||
this.$zoomFactorSelect.on('change', () => { zoomService.setZoomFactorAndSave(this.$zoomFactorSelect.val()); });
|
||||
|
||||
this.$oneTabDisplaySelect.on('change', () => {
|
||||
const hideTabRowForOneTab = this.$oneTabDisplaySelect.val() === 'hide' ? 'true' : 'false';
|
||||
this.$nativeTitleBarSelect.on('change', () => {
|
||||
const nativeTitleBarVisible = this.$nativeTitleBarSelect.val() === 'show' ? 'true' : 'false';
|
||||
|
||||
server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab)
|
||||
.then(optionsService.reloadOptions);
|
||||
});
|
||||
|
||||
this.$leftPaneMinWidth.on('change', async () => {
|
||||
await server.put('options/leftPaneMinWidth/' + this.$leftPaneMinWidth.val());
|
||||
|
||||
this.resizeLeftPanel();
|
||||
});
|
||||
|
||||
this.$leftPaneWidthPercent.on('change', async () => {
|
||||
await server.put('options/leftPaneWidthPercent/' + this.$leftPaneWidthPercent.val());
|
||||
|
||||
this.resizeLeftPanel();
|
||||
server.put('options/nativeTitleBarVisible/' + nativeTitleBarVisible);
|
||||
});
|
||||
|
||||
this.$mainFontSize.on('change', async () => {
|
||||
@@ -204,24 +159,13 @@ export default class ApperanceOptions {
|
||||
this.$zoomFactorSelect.prop('disabled', true);
|
||||
}
|
||||
|
||||
this.$oneTabDisplaySelect.val(options.hideTabRowForOneTab === 'true' ? 'hide' : 'show');
|
||||
|
||||
this.$leftPaneMinWidth.val(options.leftPaneMinWidth);
|
||||
this.$leftPaneWidthPercent.val(options.leftPaneWidthPercent);
|
||||
this.$nativeTitleBarSelect.val(options.nativeTitleBarVisible === 'true' ? 'show' : 'hide');
|
||||
|
||||
this.$mainFontSize.val(options.mainFontSize);
|
||||
this.$treeFontSize.val(options.treeFontSize);
|
||||
this.$detailFontSize.val(options.detailFontSize);
|
||||
}
|
||||
|
||||
resizeLeftPanel() {
|
||||
const leftPanePercent = parseInt(this.$leftPaneWidthPercent.val());
|
||||
const rightPanePercent = 100 - leftPanePercent;
|
||||
const leftPaneMinWidth = this.$leftPaneMinWidth.val();
|
||||
|
||||
this.$container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
|
||||
}
|
||||
|
||||
applyFontSizes() {
|
||||
this.$body.get(0).style.setProperty("--main-font-size", this.$mainFontSize.val() + "%");
|
||||
this.$body.get(0).style.setProperty("--tree-font-size", this.$treeFontSize.val() + "%");
|
||||
|
||||
141
src/public/javascripts/dialogs/options/keyboard_shortcuts.js
Normal file
141
src/public/javascripts/dialogs/options/keyboard_shortcuts.js
Normal file
@@ -0,0 +1,141 @@
|
||||
import server from "../../services/server.js";
|
||||
import utils from "../../services/utils.js";
|
||||
|
||||
const TPL = `
|
||||
<h4>Keyboard shortcuts</h4>
|
||||
|
||||
<p>Multiple shortcuts for the same action can be separated by comma.</p>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="keyboard-shortcut-filter" placeholder="Type text to filter shortcuts...">
|
||||
</div>
|
||||
|
||||
<div style="overflow: auto; height: 500px;">
|
||||
<table id="keyboard-shortcut-table" cellpadding="10">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Action name</th>
|
||||
<th>Shortcuts</th>
|
||||
<th>Default shortcuts</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<button class="btn btn-primary" id="options-keyboard-shortcuts-reload-app">Reload app to apply changes</button>
|
||||
|
||||
<button class="btn" id="options-keyboard-shortcuts-set-all-to-default">Set all shortcuts to the default</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
let globActions;
|
||||
|
||||
export default class KeyboardShortcutsOptions {
|
||||
constructor() {
|
||||
$("#options-keyboard-shortcuts").html(TPL);
|
||||
|
||||
$("#options-keyboard-shortcuts-reload-app").on("click", () => utils.reloadApp());
|
||||
|
||||
const $table = $("#keyboard-shortcut-table tbody");
|
||||
|
||||
server.get('keyboard-actions').then(actions => {
|
||||
globActions = actions;
|
||||
|
||||
for (const action of actions) {
|
||||
const $tr = $("<tr>");
|
||||
|
||||
if (action.separator) {
|
||||
$tr.append(
|
||||
$('<td colspan="4">')
|
||||
.attr("style","background-color: var(--accented-background-color); font-weight: bold;")
|
||||
.text(action.separator)
|
||||
)
|
||||
}
|
||||
else {
|
||||
$tr.append($("<td>").text(action.actionName))
|
||||
.append($("<td>").append(
|
||||
$(`<input type="text" class="form-control">`)
|
||||
.val(action.effectiveShortcuts.join(", "))
|
||||
.attr('data-keyboard-action-name', action.actionName)
|
||||
.attr('data-default-keyboard-shortcuts', action.defaultShortcuts.join(", "))
|
||||
)
|
||||
)
|
||||
.append($("<td>").text(action.defaultShortcuts.join(", ")))
|
||||
.append($("<td>").text(action.description));
|
||||
}
|
||||
|
||||
$table.append($tr);
|
||||
}
|
||||
});
|
||||
|
||||
$table.on('change', 'input.form-control', e => {
|
||||
const $input = $(e.target);
|
||||
const actionName = $input.attr('data-keyboard-action-name');
|
||||
const shortcuts = $input.val()
|
||||
.replace('+,', "+Comma")
|
||||
.split(",")
|
||||
.map(shortcut => shortcut.replace("+Comma", "+,"))
|
||||
.filter(shortcut => !!shortcut);
|
||||
|
||||
const opts = {};
|
||||
opts['keyboardShortcuts' + actionName] = JSON.stringify(shortcuts);
|
||||
|
||||
server.put('options', opts);
|
||||
});
|
||||
|
||||
$("#options-keyboard-shortcuts-set-all-to-default").on('click', async () => {
|
||||
const confirmDialog = await import('../confirm.js');
|
||||
|
||||
if (!await confirmDialog.confirm("Do you really want to reset all keyboard shortcuts to the default?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
$table.find('input.form-control').each(function() {
|
||||
const defaultShortcuts = $(this).attr('data-default-keyboard-shortcuts');
|
||||
|
||||
if ($(this).val() !== defaultShortcuts) {
|
||||
$(this)
|
||||
.val(defaultShortcuts)
|
||||
.trigger('change');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const $filter = $("#keyboard-shortcut-filter");
|
||||
|
||||
$filter.on('keyup', () => {
|
||||
const filter = $filter.val().trim().toLowerCase();
|
||||
|
||||
$table.find("tr").each((i, el) => {
|
||||
if (!filter) {
|
||||
$(el).show();
|
||||
return;
|
||||
}
|
||||
|
||||
const actionName = $(el).find('input').attr('data-keyboard-action-name');
|
||||
|
||||
if (!actionName) {
|
||||
$(el).hide();
|
||||
return;
|
||||
}
|
||||
|
||||
const action = globActions.find(act => act.actionName === actionName);
|
||||
|
||||
if (!action) {
|
||||
$(el).hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$(el).toggle(!!( // !! to avoid toggle overloads with different behavior
|
||||
action.actionName.toLowerCase().includes(filter)
|
||||
|| action.defaultShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter))
|
||||
|| action.effectiveShortcuts.some(shortcut => shortcut.toLowerCase().includes(filter))
|
||||
|| (action.description && action.description.toLowerCase().includes(filter))
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ const TPL = `
|
||||
<div>
|
||||
<h4>Spell check</h4>
|
||||
|
||||
<p>These options apply only for desktop builds, browsers will use their own native spell check.</p>
|
||||
<p>These options apply only for desktop builds, browsers will use their own native spell check. App restart is required after change.</p>
|
||||
|
||||
<div class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input" id="spell-check-enabled">
|
||||
@@ -17,7 +17,7 @@ const TPL = `
|
||||
|
||||
<div class="form-group">
|
||||
<label for="spell-check-language-code">Language code</label>
|
||||
<input type="email" class="form-control" id="spell-check-language-code" placeholder="for example "en-US", "de-AT"">
|
||||
<input type="text" class="form-control" id="spell-check-language-code" placeholder="for example "en-US", "de-AT"">
|
||||
</div>
|
||||
|
||||
<p>Changes to the spell check options will take effect after application restart.</p>
|
||||
@@ -37,6 +37,20 @@ const TPL = `
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Note erasure timeout</h4>
|
||||
|
||||
<p>Deleted notes are at first only marked as deleted and it is possible to recover them
|
||||
from Recent Notes dialog. After period of time, deleted notes are "erased" which means
|
||||
their content is not recoverable anymore. This setting allows you to configure the length
|
||||
of the period between deleting and erasing the note.</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="erase-notes-after-time-in-seconds">Erase notes after X seconds</label>
|
||||
<input class="form-control" id="erase-notes-after-time-in-seconds" type="number" min="0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Protected session timeout</h4>
|
||||
|
||||
@@ -81,6 +95,20 @@ export default class ProtectedSessionOptions {
|
||||
return false;
|
||||
});
|
||||
|
||||
this.$eraseNotesAfterTimeInSeconds = $("#erase-notes-after-time-in-seconds");
|
||||
|
||||
this.$eraseNotesAfterTimeInSeconds.on('change', () => {
|
||||
const eraseNotesAfterTimeInSeconds = this.$eraseNotesAfterTimeInSeconds.val();
|
||||
|
||||
server.put('options', { 'eraseNotesAfterTimeInSeconds': eraseNotesAfterTimeInSeconds }).then(() => {
|
||||
optionsService.reloadOptions();
|
||||
|
||||
toastService.showMessage("Options change have been saved.");
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
this.$protectedSessionTimeout = $("#protected-session-timeout-in-seconds");
|
||||
|
||||
this.$protectedSessionTimeout.on('change', () => {
|
||||
@@ -126,10 +154,11 @@ export default class ProtectedSessionOptions {
|
||||
this.$spellCheckEnabled.prop("checked", options['spellCheckEnabled'] === 'true');
|
||||
this.$spellCheckLanguageCode.val(options['spellCheckLanguageCode']);
|
||||
|
||||
this.$eraseNotesAfterTimeInSeconds.val(options['eraseNotesAfterTimeInSeconds']);
|
||||
this.$protectedSessionTimeout.val(options['protectedSessionTimeout']);
|
||||
this.$noteRevisionsTimeInterval.val(options['noteRevisionSnapshotTimeInterval']);
|
||||
|
||||
this.$imageMaxWidthHeight.val(options['imageMaxWidthHeight']);
|
||||
this.$imageJpegQuality.val(options['imageJpegQuality']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,45 +3,6 @@ import server from "../../services/server.js";
|
||||
import optionsService from "../../services/options.js";
|
||||
|
||||
const TPL = `
|
||||
<h4>Show sidebar in new tab</h4>
|
||||
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="show-sidebar-in-new-tab">
|
||||
<label class="form-check-label" for="show-sidebar-in-new-tab">Show sidebar in new tab</label>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<h4>Sidebar sizing</h4>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-6">
|
||||
<label for="sidebar-min-width">Sidebar minimum width (in pixels)</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="sidebar-min-width" min="100" max="2000" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">px</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-6">
|
||||
<label for="left-pane-min-width">Sidebar width percent of the detail pane</label>
|
||||
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="sidebar-width-percent" min="0" max="70" step="1"/>
|
||||
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Sidebar width is calculated from the percent of the detail pane, if this is smaller than minimum width, then minimum width is used. If you want to have fixed width sidebar, set minimum width to the desired width and set percent to 0.</p>
|
||||
|
||||
<h4>Widgets</h4>
|
||||
|
||||
<div id="widgets-configuration" class="row">
|
||||
@@ -58,48 +19,15 @@ export default class SidebarOptions {
|
||||
constructor() {
|
||||
$("#options-sidebar").html(TPL);
|
||||
|
||||
this.$sidebarMinWidth = $("#sidebar-min-width");
|
||||
this.$sidebarWidthPercent = $("#sidebar-width-percent");
|
||||
this.$showSidebarInNewTab = $("#show-sidebar-in-new-tab");
|
||||
this.$widgetsConfiguration = $("#widgets-configuration");
|
||||
this.$widgetsEnabled = $("#widgets-enabled");
|
||||
this.$widgetsDisabled = $("#widgets-disabled");
|
||||
|
||||
this.$sidebarMinWidth.on('change', async () => {
|
||||
await server.put('options/sidebarMinWidth/' + this.$sidebarMinWidth.val());
|
||||
|
||||
this.resizeSidebar();
|
||||
});
|
||||
|
||||
this.$sidebarWidthPercent.on('change', async () => {
|
||||
await server.put('options/sidebarWidthPercent/' + this.$sidebarWidthPercent.val());
|
||||
|
||||
this.resizeSidebar();
|
||||
});
|
||||
|
||||
this.$showSidebarInNewTab.on('change', async () => {
|
||||
const flag = this.$showSidebarInNewTab.is(":checked") ? 'true' : 'false';
|
||||
|
||||
await server.put('options/showSidebarInNewTab/' + flag);
|
||||
|
||||
optionsService.reloadOptions();
|
||||
});
|
||||
}
|
||||
|
||||
async optionsLoaded(options) {
|
||||
this.$widgetsEnabled.empty();
|
||||
this.$widgetsDisabled.empty();
|
||||
|
||||
this.$sidebarMinWidth.val(options.sidebarMinWidth);
|
||||
this.$sidebarWidthPercent.val(options.sidebarWidthPercent);
|
||||
|
||||
if (parseInt(options.showSidebarInNewTab)) {
|
||||
this.$showSidebarInNewTab.attr("checked", "checked");
|
||||
}
|
||||
else {
|
||||
this.$showSidebarInNewTab.removeAttr("checked");
|
||||
}
|
||||
|
||||
const widgets = [
|
||||
{name: 'attributes', title: 'Attributes'},
|
||||
{name: 'linkMap', title: 'Link map'},
|
||||
@@ -188,19 +116,4 @@ export default class SidebarOptions {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
resizeSidebar() {
|
||||
const sidebarWidthPercent = parseInt(this.$sidebarWidthPercent.val());
|
||||
const sidebarMinWidth = this.$sidebarMinWidth.val();
|
||||
|
||||
// need to find them dynamically since they change
|
||||
const $sidebar = $(".note-detail-sidebar");
|
||||
|
||||
const $content = $(".note-detail-content");
|
||||
|
||||
$sidebar.css("width", sidebarWidthPercent + '%');
|
||||
$sidebar.css("min-width", sidebarMinWidth + 'px');
|
||||
|
||||
$content.css("width", (100 - sidebarWidthPercent) + '%');
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ const TPL = `
|
||||
|
||||
<div class="form-group">
|
||||
<label for="sync-server-timeout">Sync timeout (milliseconds)</label>
|
||||
<input class="form-control" id="sync-server-timeout" min="1" max="10000000" type="number">
|
||||
<input class="form-control" id="sync-server-timeout" min="1" max="10000000" type="number" style="text-align: left;">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@@ -25,7 +25,7 @@ const TPL = `
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
|
||||
<button class="btn btn-secondary" type="button" data-help-page="Synchronization">Help</button>
|
||||
<button class="btn" type="button" data-help-page="Synchronization">Help</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -35,7 +35,7 @@ const TPL = `
|
||||
|
||||
<p>This will test connection and handshake to the sync server. If sync server isn't initialized, this will set it up to sync with local document.</p>
|
||||
|
||||
<button id="test-sync-button" class="btn btn-secondary">Test sync</button>`;
|
||||
<button id="test-sync-button" class="btn">Test sync</button>`;
|
||||
|
||||
export default class SyncOptions {
|
||||
constructor() {
|
||||
|
||||
@@ -12,10 +12,6 @@ let resolve;
|
||||
let shownCb;
|
||||
|
||||
export function ask({ message, defaultValue, shown }) {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
shownCb = shown;
|
||||
|
||||
$question = $("<label>")
|
||||
@@ -34,7 +30,7 @@ export function ask({ message, defaultValue, shown }) {
|
||||
.append($question)
|
||||
.append($answer));
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
return new Promise((res, rej) => { resolve = res; });
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import protectedSessionService from "../services/protected_session.js";
|
||||
import utils from "../services/utils.js";
|
||||
|
||||
const $dialog = $("#protected-session-password-dialog");
|
||||
const $passwordForm = $dialog.find(".protected-session-password-form");
|
||||
const $passwordInput = $dialog.find(".protected-session-password");
|
||||
|
||||
export function show() {
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
$passwordInput.trigger('focus');
|
||||
}
|
||||
|
||||
@@ -8,11 +8,7 @@ const $dialog = $("#recent-changes-dialog");
|
||||
const $content = $("#recent-changes-content");
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
|
||||
const result = await server.get('recent-changes');
|
||||
|
||||
@@ -28,28 +24,60 @@ export async function showDialog() {
|
||||
const groupedByDate = groupByDate(result);
|
||||
|
||||
for (const [dateDay, dayChanges] of groupedByDate) {
|
||||
const changesListEl = $('<ul>');
|
||||
const $changesList = $('<ul>');
|
||||
|
||||
const dayEl = $('<div>').append($('<b>').html(utils.formatDate(dateDay))).append(changesListEl);
|
||||
const dayEl = $('<div>').append($('<b>').html(utils.formatDate(dateDay))).append($changesList);
|
||||
|
||||
for (const change of dayChanges) {
|
||||
const formattedTime = utils.formatTime(utils.parseDate(change.date));
|
||||
|
||||
let noteLink;
|
||||
let $noteLink;
|
||||
|
||||
if (change.current_isDeleted) {
|
||||
noteLink = change.current_title;
|
||||
$noteLink = $("<span>").text(change.current_title);
|
||||
|
||||
if (change.canBeUndeleted) {
|
||||
const $undeleteLink = $(`<a href="javascript:">`)
|
||||
.text("undelete")
|
||||
.on('click', async () => {
|
||||
const confirmDialog = await import('../dialogs/confirm.js');
|
||||
const text = 'Do you want to undelete this note and its sub-notes?';
|
||||
|
||||
if (await confirmDialog.confirm(text)) {
|
||||
await server.put(`notes/${change.noteId}/undelete`);
|
||||
|
||||
$dialog.modal('hide');
|
||||
|
||||
await treeCache.reloadNotes([change.noteId]);
|
||||
|
||||
treeService.activateNote(change.noteId);
|
||||
}
|
||||
});
|
||||
|
||||
$noteLink
|
||||
.append(' (')
|
||||
.append($undeleteLink)
|
||||
.append(')');
|
||||
}
|
||||
}
|
||||
else {
|
||||
const note = await treeCache.getNote(change.noteId);
|
||||
const notePath = await treeService.getSomeNotePath(note);
|
||||
|
||||
noteLink = await linkService.createNoteLinkWithPath(notePath, change.title);
|
||||
if (notePath) {
|
||||
$noteLink = await linkService.createNoteLink(notePath, {
|
||||
title: change.title,
|
||||
showNotePath: true
|
||||
});
|
||||
}
|
||||
else {
|
||||
$noteLink = $("<span>").text(note.title);
|
||||
}
|
||||
}
|
||||
|
||||
changesListEl.append($('<li>')
|
||||
$changesList.append($('<li>')
|
||||
.append(formattedTime + ' - ')
|
||||
.append(noteLink));
|
||||
.append($noteLink));
|
||||
}
|
||||
|
||||
$content.append(dayEl);
|
||||
@@ -82,5 +110,6 @@ function groupByDate(result) {
|
||||
|
||||
groupedByDate.get(dateDay).push(row);
|
||||
}
|
||||
|
||||
return groupedByDate;
|
||||
}
|
||||
|
||||
@@ -6,22 +6,17 @@ import utils from "../services/utils.js";
|
||||
const $dialog = $("#sql-console-dialog");
|
||||
const $query = $('#sql-console-query');
|
||||
const $executeButton = $('#sql-console-execute');
|
||||
const $resultHead = $('#sql-console-results thead');
|
||||
const $resultBody = $('#sql-console-results tbody');
|
||||
const $tables = $("#sql-console-tables");
|
||||
const $tableSchemas = $("#sql-console-table-schemas");
|
||||
const $resultContainer = $("#result-container");
|
||||
|
||||
let codeEditor;
|
||||
|
||||
$dialog.on("shown.bs.modal", e => initEditor());
|
||||
|
||||
export async function showDialog() {
|
||||
utils.closeActiveDialog();
|
||||
await showTableSchemas();
|
||||
|
||||
glob.activeDialog = $dialog;
|
||||
|
||||
await showTables();
|
||||
|
||||
$dialog.modal();
|
||||
utils.openDialog($dialog);
|
||||
}
|
||||
|
||||
async function initEditor() {
|
||||
@@ -45,6 +40,10 @@ async function initEditor() {
|
||||
|
||||
codeEditor.setOption("mode", "text/x-sqlite");
|
||||
CodeMirror.autoLoadMode(codeEditor, "sql");
|
||||
|
||||
codeEditor.setValue(`SELECT title, isProtected, type, mime FROM notes WHERE noteId = 'root';
|
||||
---
|
||||
SELECT noteId, parentNoteId, notePosition, prefix FROM branches WHERE branchId = 'root';`);
|
||||
}
|
||||
|
||||
codeEditor.focus();
|
||||
@@ -70,55 +69,66 @@ async function execute() {
|
||||
toastService.showMessage("Query was executed successfully.");
|
||||
}
|
||||
|
||||
const rows = result.rows;
|
||||
const results = result.results;
|
||||
|
||||
$resultHead.empty();
|
||||
$resultBody.empty();
|
||||
$resultContainer.empty();
|
||||
|
||||
for (const rows of results) {
|
||||
if (rows.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const $table = $('<table class="table table-striped">');
|
||||
$resultContainer.append($table);
|
||||
|
||||
if (rows.length > 0) {
|
||||
const result = rows[0];
|
||||
const rowEl = $("<tr>");
|
||||
const $row = $("<tr>");
|
||||
|
||||
for (const key in result) {
|
||||
rowEl.append($("<th>").html(key));
|
||||
$row.append($("<th>").html(key));
|
||||
}
|
||||
|
||||
$resultHead.append(rowEl);
|
||||
}
|
||||
$table.append($row);
|
||||
|
||||
for (const result of rows) {
|
||||
const rowEl = $("<tr>");
|
||||
for (const result of rows) {
|
||||
const $row = $("<tr>");
|
||||
|
||||
for (const key in result) {
|
||||
rowEl.append($("<td>").html(result[key]));
|
||||
for (const key in result) {
|
||||
$row.append($("<td>").html(result[key]));
|
||||
}
|
||||
|
||||
$table.append($row);
|
||||
}
|
||||
|
||||
$resultBody.append(rowEl);
|
||||
}
|
||||
}
|
||||
|
||||
async function showTables() {
|
||||
async function showTableSchemas() {
|
||||
const tables = await server.get('sql/schema');
|
||||
|
||||
$tables.empty();
|
||||
$tableSchemas.empty();
|
||||
|
||||
for (const table of tables) {
|
||||
const $tableLink = $('<button class="btn">').text(table.name);
|
||||
|
||||
const $columns = $("<table>");
|
||||
const $columns = $("<ul>");
|
||||
|
||||
for (const column of table.columns) {
|
||||
$columns.append(
|
||||
$("<tr>")
|
||||
.append($("<td>").text(column.name))
|
||||
.append($("<td>").text(column.type))
|
||||
$("<li>")
|
||||
.append($("<span>").text(column.name))
|
||||
.append($("<span>").text(column.type))
|
||||
);
|
||||
}
|
||||
|
||||
$tables.append($tableLink).append(" ");
|
||||
$tableSchemas.append($tableLink).append(" ");
|
||||
|
||||
$tableLink
|
||||
.tooltip({html: true, title: $columns.html()})
|
||||
.tooltip({
|
||||
html: true,
|
||||
placement: 'bottom',
|
||||
boundary: 'window',
|
||||
title: $columns[0].outerHTML
|
||||
})
|
||||
.on('click', () => codeEditor.setValue("SELECT * FROM " + table.name + " LIMIT 100"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ class Branch {
|
||||
this.branchId = row.branchId;
|
||||
/** @param {string} */
|
||||
this.noteId = row.noteId;
|
||||
this.note = null;
|
||||
/** @param {string} */
|
||||
this.parentNoteId = row.parentNoteId;
|
||||
/** @param {int} */
|
||||
@@ -19,7 +18,7 @@ class Branch {
|
||||
|
||||
/** @returns {NoteShort} */
|
||||
async getNote() {
|
||||
return await this.treeCache.getNote(this.noteId);
|
||||
return this.treeCache.getNote(this.noteId);
|
||||
}
|
||||
|
||||
/** @returns {boolean} true if it's top level, meaning its parent is root note */
|
||||
|
||||
@@ -154,20 +154,27 @@ class NoteShort {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} [name] - attribute name to filter
|
||||
* @returns {Promise<Attribute[]>}
|
||||
* @param {string} [type] - (optional) attribute type to filter
|
||||
* @param {string} [name] - (optional) attribute name to filter
|
||||
* @returns {Promise<Attribute[]>} all note's attributes, including inherited ones
|
||||
*/
|
||||
async getAttributes(name) {
|
||||
if (!this.attributeCache) {
|
||||
this.attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
|
||||
async getAttributes(type, name) {
|
||||
if (!this.__attributeCache) {
|
||||
this.__attributeCache = (await server.get('notes/' + this.noteId + '/attributes'))
|
||||
.map(attrRow => new Attribute(this.treeCache, attrRow));
|
||||
}
|
||||
|
||||
if (name) {
|
||||
return this.attributeCache.filter(attr => attr.name === name);
|
||||
if (type && name) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type && attr.name === name);
|
||||
}
|
||||
else if (type) {
|
||||
return this.__attributeCache.filter(attr => attr.type === type);
|
||||
}
|
||||
else if (name) {
|
||||
return this.__attributeCache.filter(attr => attr.name === name);
|
||||
}
|
||||
else {
|
||||
return this.attributeCache;
|
||||
return this.__attributeCache.slice();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +183,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
|
||||
*/
|
||||
async getLabels(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
|
||||
return await this.getAttributes(LABEL, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -184,7 +191,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
|
||||
*/
|
||||
async getLabelDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
|
||||
return await this.getAttributes(LABEL_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +199,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
|
||||
*/
|
||||
async getRelations(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
|
||||
return await this.getAttributes(RELATION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,7 +207,7 @@ class NoteShort {
|
||||
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
|
||||
*/
|
||||
async getRelationDefinitions(name) {
|
||||
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
|
||||
return await this.getAttributes(RELATION_DEFINITION, name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -299,8 +306,8 @@ class NoteShort {
|
||||
* Clear note's attributes cache to force fresh reload for next attribute request.
|
||||
* Cache is note instance scoped.
|
||||
*/
|
||||
invalidateAttributeCache() {
|
||||
this.attributeCache = null;
|
||||
invalidate__attributeCache() {
|
||||
this.__attributeCache = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +328,7 @@ class NoteShort {
|
||||
const dto = Object.assign({}, this);
|
||||
delete dto.treeCache;
|
||||
delete dto.archived;
|
||||
delete dto.attributeCache;
|
||||
delete dto.__attributeCache;
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,26 @@ import contextMenuWidget from "./services/context_menu.js";
|
||||
import treeChangesService from "./services/branches.js";
|
||||
import utils from "./services/utils.js";
|
||||
import treeUtils from "./services/tree_utils.js";
|
||||
import linkService from "./services/link.js";
|
||||
import noteContentRenderer from "./services/note_content_renderer.js";
|
||||
|
||||
window.glob.isDesktop = utils.isDesktop;
|
||||
window.glob.isMobile = utils.isMobile;
|
||||
window.glob.showAddLinkDialog = () => import('./dialogs/add_link.js').then(d => d.showDialog());
|
||||
window.glob.showIncludeNoteDialog = cb => import('./dialogs/include_note.js').then(d => d.showDialog(cb));
|
||||
window.glob.loadIncludedNote = async (noteId, el) => {
|
||||
const note = await treeCache.getNote(noteId);
|
||||
|
||||
if (note) {
|
||||
$(el).empty().append($("<h3>").append(await linkService.createNoteLink(note.noteId, {
|
||||
showTooltip: false
|
||||
})));
|
||||
|
||||
const {renderedContent} = await noteContentRenderer.getRenderedContent(note);
|
||||
|
||||
$(el).append(renderedContent);
|
||||
}
|
||||
};
|
||||
|
||||
const $leftPane = $("#left-pane");
|
||||
const $tree = $("#tree");
|
||||
@@ -37,12 +54,12 @@ $detail.on("click", ".close-detail-button",() => {
|
||||
});
|
||||
|
||||
async function showTree() {
|
||||
const tree = await treeService.loadTree();
|
||||
const treeData = await treeService.loadTreeData();
|
||||
|
||||
$tree.fancytree({
|
||||
autoScroll: true,
|
||||
extensions: ["dnd5", "clones"],
|
||||
source: tree,
|
||||
source: treeData,
|
||||
scrollParent: $tree,
|
||||
minExpandLevel: 2, // root can't be collapsed
|
||||
click: (event, data) => {
|
||||
@@ -87,6 +104,8 @@ async function showTree() {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
treeService.setTree($.ui.fancytree.getTree("#tree"));
|
||||
}
|
||||
|
||||
$detail.on("click", ".note-menu-button", async e => {
|
||||
|
||||
@@ -265,6 +265,24 @@ ws.subscribeToMessages(async message => {
|
||||
}
|
||||
});
|
||||
|
||||
ws.subscribeToMessages(async message => {
|
||||
if (message.taskType !== 'undelete-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, "Undeleting notes in progress: " + message.progressCount));
|
||||
} else if (message.type === 'task-succeeded') {
|
||||
const toast = makeToast(message.taskId, "Undeleting notes finished successfully.");
|
||||
toast.closeAfter = 5000;
|
||||
|
||||
toastService.showPersistent(toast);
|
||||
}
|
||||
});
|
||||
|
||||
export default {
|
||||
moveBeforeNode,
|
||||
moveAfterNode,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import treeUtils from "./tree_utils.js";
|
||||
import treeService from "./tree.js";
|
||||
import treeChangesService from "./branches.js";
|
||||
import cloningService from "./cloning.js";
|
||||
import toastService from "./toast.js";
|
||||
@@ -19,7 +19,7 @@ async function pasteAfter(afterNode) {
|
||||
}
|
||||
|
||||
if (clipboardMode === 'cut') {
|
||||
const nodes = clipboardNodeKeys.map(nodeKey => treeUtils.getNodeByKey(nodeKey));
|
||||
const nodes = clipboardNodeKeys.map(nodeKey => treeService.getNodeByKey(nodeKey));
|
||||
|
||||
await treeChangesService.moveAfterNode(nodes, afterNode);
|
||||
|
||||
@@ -28,7 +28,7 @@ async function pasteAfter(afterNode) {
|
||||
}
|
||||
else if (clipboardMode === 'copy') {
|
||||
for (const nodeKey of clipboardNodeKeys) {
|
||||
const clipNode = treeUtils.getNodeByKey(nodeKey);
|
||||
const clipNode = treeService.getNodeByKey(nodeKey);
|
||||
|
||||
await cloningService.cloneNoteAfter(clipNode.data.noteId, afterNode.data.branchId);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ async function pasteInto(parentNode) {
|
||||
}
|
||||
|
||||
if (clipboardMode === 'cut') {
|
||||
const nodes = clipboardNodeKeys.map(nodeKey => treeUtils.getNodeByKey(nodeKey));
|
||||
const nodes = clipboardNodeKeys.map(nodeKey => treeService.getNodeByKey(nodeKey));
|
||||
|
||||
await treeChangesService.moveToNode(nodes, parentNode);
|
||||
|
||||
@@ -57,7 +57,7 @@ async function pasteInto(parentNode) {
|
||||
}
|
||||
else if (clipboardMode === 'copy') {
|
||||
for (const nodeKey of clipboardNodeKeys) {
|
||||
const clipNode = treeUtils.getNodeByKey(nodeKey);
|
||||
const clipNode = treeService.getNodeByKey(nodeKey);
|
||||
|
||||
await cloningService.cloneNoteTo(clipNode.data.noteId, parentNode.data.noteId);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ function cut(nodes) {
|
||||
}
|
||||
|
||||
function isClipboardEmpty() {
|
||||
clipboardNodeKeys = clipboardNodeKeys.filter(key => !!treeUtils.getNodeByKey(key));
|
||||
clipboardNodeKeys = clipboardNodeKeys.filter(key => !!treeService.getNodeByKey(key));
|
||||
|
||||
return clipboardNodeKeys.length === 0;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import keyboardActionService from './keyboard_actions.js';
|
||||
const $contextMenuContainer = $("#context-menu-container");
|
||||
|
||||
let dateContextMenuOpenedMs = 0;
|
||||
@@ -69,12 +70,13 @@ async function initContextMenu(event, contextMenu) {
|
||||
|
||||
addItems($contextMenuContainer, await contextMenu.getContextMenuItems());
|
||||
|
||||
keyboardActionService.updateDisplayedShortcuts($contextMenuContainer);
|
||||
|
||||
// code below tries to detect when dropdown would overflow from page
|
||||
// in such case we'll position it above click coordinates so it will fit into client
|
||||
const clickPosition = event.pageY;
|
||||
const clientHeight = document.documentElement.clientHeight;
|
||||
const contextMenuHeight = $contextMenuContainer.height();
|
||||
|
||||
const contextMenuHeight = $contextMenuContainer.outerHeight() + 30;
|
||||
let top;
|
||||
|
||||
if (clickPosition + contextMenuHeight > clientHeight) {
|
||||
|
||||
@@ -4,6 +4,12 @@ import zoomService from "./zoom.js";
|
||||
import protectedSessionService from "./protected_session.js";
|
||||
import searchNotesService from "./search_notes.js";
|
||||
import treeService from "./tree.js";
|
||||
import dateNoteService from "./date_notes.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
import keyboardActionService from "./keyboard_actions.js";
|
||||
import hoistedNoteService from "./hoisted_note.js";
|
||||
import treeCache from "./tree_cache.js";
|
||||
import server from "./server.js";
|
||||
|
||||
const NOTE_REVISIONS = "../dialogs/note_revisions.js";
|
||||
const OPTIONS = "../dialogs/options.js";
|
||||
@@ -12,6 +18,7 @@ const JUMP_TO_NOTE = "../dialogs/jump_to_note.js";
|
||||
const NOTE_SOURCE = "../dialogs/note_source.js";
|
||||
const RECENT_CHANGES = "../dialogs/recent_changes.js";
|
||||
const SQL_CONSOLE = "../dialogs/sql_console.js";
|
||||
const BACKEND_LOG = "../dialogs/backend_log.js";
|
||||
const ATTRIBUTES = "../dialogs/attributes.js";
|
||||
const HELP = "../dialogs/help.js";
|
||||
const NOTE_INFO = "../dialogs/note_info.js";
|
||||
@@ -26,92 +33,123 @@ function registerEntrypoints() {
|
||||
jQuery.hotkeys.options.filterContentEditable = false;
|
||||
jQuery.hotkeys.options.filterTextInputs = false;
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+l', () => import(ADD_LINK).then(d => d.showDialog()));
|
||||
utils.bindGlobalShortcut('ctrl+shift+l', () => import(ADD_LINK).then(d => d.showDialogForClone()));
|
||||
keyboardActionService.setGlobalActionHandler("AddLinkToText", () => import(ADD_LINK).then(d => d.showDialog()));
|
||||
|
||||
$("#jump-to-note-dialog-button").on('click', () => import(JUMP_TO_NOTE).then(d => d.showDialog()));
|
||||
utils.bindGlobalShortcut('ctrl+j', () => import(JUMP_TO_NOTE).then(d => d.showDialog()));
|
||||
const showJumpToNoteDialog = () => import(JUMP_TO_NOTE).then(d => d.showDialog());
|
||||
$("#jump-to-note-dialog-button").on('click', showJumpToNoteDialog);
|
||||
keyboardActionService.setGlobalActionHandler("JumpToNote", showJumpToNoteDialog);
|
||||
|
||||
$("#recent-changes-button").on('click', () => import(RECENT_CHANGES).then(d => d.showDialog()));
|
||||
const showRecentChanges = () => import(RECENT_CHANGES).then(d => d.showDialog());
|
||||
$("#recent-changes-button").on('click', showRecentChanges);
|
||||
keyboardActionService.setGlobalActionHandler("ShowRecentChanges", showRecentChanges);
|
||||
|
||||
$("#enter-protected-session-button").on('click', protectedSessionService.enterProtectedSession);
|
||||
$("#leave-protected-session-button").on('click', protectedSessionService.leaveProtectedSession);
|
||||
|
||||
$("#toggle-search-button").on('click', searchNotesService.toggleSearch);
|
||||
utils.bindGlobalShortcut('ctrl+s', searchNotesService.toggleSearch);
|
||||
keyboardActionService.setGlobalActionHandler('SearchNotes', searchNotesService.toggleSearch);
|
||||
|
||||
const $noteTabContainer = $("#note-tab-container");
|
||||
$noteTabContainer.on("click", ".show-attributes-button", () => import(ATTRIBUTES).then(d => d.showDialog()));
|
||||
utils.bindGlobalShortcut('alt+a', () => import(ATTRIBUTES).then(d => d.showDialog()));
|
||||
|
||||
$noteTabContainer.on("click", ".show-note-info-button", () => import(NOTE_INFO).then(d => d.showDialog()));
|
||||
const showAttributesDialog = () => import(ATTRIBUTES).then(d => d.showDialog());
|
||||
$noteTabContainer.on("click", ".show-attributes-button", showAttributesDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowAttributes", showAttributesDialog);
|
||||
|
||||
$noteTabContainer.on("click", ".show-note-revisions-button", function() {
|
||||
const showNoteInfoDialog = () => import(NOTE_INFO).then(d => d.showDialog());
|
||||
$noteTabContainer.on("click", ".show-note-info-button", showNoteInfoDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowNoteInfo", showNoteInfoDialog);
|
||||
|
||||
const showNoteRevisionsDialog = function() {
|
||||
if ($(this).hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
import(NOTE_REVISIONS).then(d => d.showCurrentNoteRevisions());
|
||||
});
|
||||
};
|
||||
|
||||
$noteTabContainer.on("click", ".show-source-button", function() {
|
||||
$noteTabContainer.on("click", ".show-note-revisions-button", showNoteRevisionsDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowNoteRevisions", showNoteRevisionsDialog);
|
||||
|
||||
const showNoteSourceDialog = function() {
|
||||
if ($(this).hasClass("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
import(NOTE_SOURCE).then(d => d.showDialog());
|
||||
});
|
||||
};
|
||||
|
||||
$noteTabContainer.on("click", ".show-link-map-button", function() {
|
||||
import(LINK_MAP).then(d => d.showDialog());
|
||||
});
|
||||
$noteTabContainer.on("click", ".show-source-button", showNoteSourceDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowNoteSource", showNoteSourceDialog);
|
||||
|
||||
$("#options-button").on('click', () => import(OPTIONS).then(d => d.showDialog()));
|
||||
const showLinkMapDialog = () => import(LINK_MAP).then(d => d.showDialog());
|
||||
$noteTabContainer.on("click", ".show-link-map-button", showLinkMapDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowLinkMap", showLinkMapDialog);
|
||||
|
||||
$("#show-help-button").on('click', () => import(HELP).then(d => d.showDialog()));
|
||||
utils.bindGlobalShortcut('f1', () => import(HELP).then(d => d.showDialog()));
|
||||
const showOptionsDialog = () => import(OPTIONS).then(d => d.showDialog());
|
||||
$("#options-button").on('click', showOptionsDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowOptions", showOptionsDialog);
|
||||
|
||||
$("#open-sql-console-button").on('click', () => import(SQL_CONSOLE).then(d => d.showDialog()));
|
||||
utils.bindGlobalShortcut('alt+o', () => import(SQL_CONSOLE).then(d => d.showDialog()));
|
||||
const showHelpDialog = () => import(HELP).then(d => d.showDialog());
|
||||
$("#show-help-button").on('click', showHelpDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowHelp", showHelpDialog);
|
||||
|
||||
const showSqlConsoleDialog = () => import(SQL_CONSOLE).then(d => d.showDialog());
|
||||
$("#open-sql-console-button").on('click', showSqlConsoleDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowSQLConsole", showSqlConsoleDialog);
|
||||
|
||||
const showBackendLogDialog = () => import(BACKEND_LOG).then(d => d.showDialog());
|
||||
$("#show-backend-log-button").on('click', showBackendLogDialog);
|
||||
keyboardActionService.setGlobalActionHandler("ShowBackendLog", showBackendLogDialog);
|
||||
|
||||
$("#show-about-dialog-button").on('click', () => import(ABOUT).then(d => d.showDialog()));
|
||||
|
||||
if (utils.isElectron()) {
|
||||
$("#history-navigation").show();
|
||||
$("#history-back-button").on('click', window.history.back);
|
||||
$("#history-forward-button").on('click', window.history.forward);
|
||||
keyboardActionService.setGlobalActionHandler("BackInNoteHistory", window.history.back);
|
||||
|
||||
if (utils.isMac()) {
|
||||
// Mac has a different history navigation shortcuts - https://github.com/zadam/trilium/issues/376
|
||||
utils.bindGlobalShortcut('meta+left', window.history.back);
|
||||
utils.bindGlobalShortcut('meta+right', window.history.forward);
|
||||
}
|
||||
else {
|
||||
utils.bindGlobalShortcut('alt+left', window.history.back);
|
||||
utils.bindGlobalShortcut('alt+right', window.history.forward);
|
||||
}
|
||||
$("#history-forward-button").on('click', window.history.forward);
|
||||
keyboardActionService.setGlobalActionHandler("ForwardInNoteHistory", window.history.forward);
|
||||
}
|
||||
|
||||
utils.bindGlobalShortcut('alt+m', e => {
|
||||
$(".hide-toggle").toggle();
|
||||
$("#container").toggleClass("distraction-free-mode");
|
||||
});
|
||||
let zenModeActive = false;
|
||||
|
||||
// hide (toggle) everything except for the note content for distraction free writing
|
||||
utils.bindGlobalShortcut('alt+t', e => {
|
||||
// hide (toggle) everything except for the note content for zen mode
|
||||
const toggleZenMode = () => {
|
||||
if (!zenModeActive) {
|
||||
$(".hide-in-zen-mode,.gutter").addClass("hidden-by-zen-mode");
|
||||
$("#container").addClass("zen-mode");
|
||||
zenModeActive = true;
|
||||
}
|
||||
else {
|
||||
// not hiding / showing explicitly since element might be hidden also for other reasons
|
||||
$(".hide-in-zen-mode,.gutter").removeClass("hidden-by-zen-mode");
|
||||
$("#container").removeClass("zen-mode");
|
||||
zenModeActive = false;
|
||||
}
|
||||
};
|
||||
|
||||
$("#toggle-zen-mode-button").on('click', toggleZenMode);
|
||||
keyboardActionService.setGlobalActionHandler("ToggleZenMode", toggleZenMode);
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("InsertDateTimeToText", () => {
|
||||
const date = new Date();
|
||||
const dateString = utils.formatDateTime(date);
|
||||
|
||||
linkService.addTextToEditor(dateString);
|
||||
});
|
||||
|
||||
utils.bindGlobalShortcut('f5', utils.reloadApp);
|
||||
|
||||
$("#reload-frontend-button").on('click', utils.reloadApp);
|
||||
utils.bindGlobalShortcut('ctrl+r', utils.reloadApp);
|
||||
keyboardActionService.setGlobalActionHandler("ReloadFrontendApp", utils.reloadApp);
|
||||
|
||||
$("#open-dev-tools-button").toggle(utils.isElectron());
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("PasteMarkdownIntoText", async () => {
|
||||
const dialog = await import("../dialogs/markdown_import.js");
|
||||
|
||||
dialog.importMarkdownInline();
|
||||
});
|
||||
|
||||
if (utils.isElectron()) {
|
||||
const openDevTools = () => {
|
||||
require('electron').remote.getCurrentWindow().toggleDevTools();
|
||||
@@ -119,8 +157,8 @@ function registerEntrypoints() {
|
||||
return false;
|
||||
};
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+shift+i', openDevTools);
|
||||
$("#open-dev-tools-button").on('click', openDevTools);
|
||||
keyboardActionService.setGlobalActionHandler("OpenDevTools", openDevTools);
|
||||
}
|
||||
|
||||
let findInPage;
|
||||
@@ -141,18 +179,16 @@ function registerEntrypoints() {
|
||||
textHoverBgColor: '#555',
|
||||
caseSelectedColor: 'var(--main-border-color)'
|
||||
});
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
utils.bindGlobalShortcut('ctrl+f', () => {
|
||||
findInPage.openFindWindow();
|
||||
|
||||
return false;
|
||||
keyboardActionService.setGlobalActionHandler("FindInText", () => {
|
||||
if (!glob.activeDialog || !glob.activeDialog.is(":visible")) {
|
||||
findInPage.openFindWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
const toggleFullscreen = function() {
|
||||
const toggleFullscreen = () => {
|
||||
const win = require('electron').remote.getCurrentWindow();
|
||||
|
||||
if (win.isFullScreenable()) {
|
||||
@@ -164,7 +200,7 @@ function registerEntrypoints() {
|
||||
|
||||
$("#toggle-fullscreen-button").on('click', toggleFullscreen);
|
||||
|
||||
utils.bindGlobalShortcut('f11', toggleFullscreen);
|
||||
keyboardActionService.setGlobalActionHandler("ToggleFullscreen", toggleFullscreen);
|
||||
}
|
||||
else {
|
||||
// outside of electron this is handled by the browser
|
||||
@@ -172,8 +208,8 @@ function registerEntrypoints() {
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
utils.bindGlobalShortcut('ctrl+-', zoomService.decreaseZoomFactor);
|
||||
utils.bindGlobalShortcut('ctrl+=', zoomService.increaseZoomFactor);
|
||||
keyboardActionService.setGlobalActionHandler("ZoomOut", zoomService.decreaseZoomFactor);
|
||||
keyboardActionService.setGlobalActionHandler("ZoomIn", zoomService.increaseZoomFactor);
|
||||
}
|
||||
|
||||
$(document).on('click', "a[data-action='note-revision']", async event => {
|
||||
@@ -188,7 +224,7 @@ function registerEntrypoints() {
|
||||
return false;
|
||||
});
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+shift+c', () => import(CLONE_TO).then(d => {
|
||||
keyboardActionService.setGlobalActionHandler("CloneNotesTo", () => import(CLONE_TO).then(d => {
|
||||
const activeNode = treeService.getActiveNode();
|
||||
|
||||
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
|
||||
@@ -198,7 +234,7 @@ function registerEntrypoints() {
|
||||
d.showDialog(noteIds);
|
||||
}));
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+shift+x', () => import(MOVE_TO).then(d => {
|
||||
keyboardActionService.setGlobalActionHandler("MoveNotesTo", () => import(MOVE_TO).then(d => {
|
||||
const activeNode = treeService.getActiveNode();
|
||||
|
||||
const selectedOrActiveNodes = treeService.getSelectedOrActiveNodes(activeNode);
|
||||
@@ -206,6 +242,54 @@ function registerEntrypoints() {
|
||||
d.showDialog(selectedOrActiveNodes);
|
||||
}));
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("CreateNoteIntoDayNote", async () => {
|
||||
const todayNote = await dateNoteService.getTodayNote();
|
||||
|
||||
const {note} = await server.post(`notes/${todayNote.noteId}/children?target=into`, {
|
||||
title: 'new note',
|
||||
content: '',
|
||||
type: 'text',
|
||||
isProtected: todayNote.isProtected
|
||||
});
|
||||
|
||||
await treeService.expandToNote(note.noteId);
|
||||
|
||||
await noteDetailService.openInTab(note.noteId, true);
|
||||
|
||||
noteDetailService.focusAndSelectTitle();
|
||||
});
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("EditBranchPrefix", async () => {
|
||||
const node = treeService.getActiveNode();
|
||||
|
||||
const editBranchPrefixDialog = await import("../dialogs/branch_prefix.js");
|
||||
editBranchPrefixDialog.showDialog(node);
|
||||
});
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("ToggleNoteHoisting", async () => {
|
||||
const node = treeService.getActiveNode();
|
||||
|
||||
hoistedNoteService.getHoistedNoteId().then(async hoistedNoteId => {
|
||||
if (node.data.noteId === hoistedNoteId) {
|
||||
hoistedNoteService.unhoist();
|
||||
}
|
||||
else {
|
||||
const note = await treeCache.getNote(node.data.noteId);
|
||||
|
||||
if (note.type !== 'search') {
|
||||
hoistedNoteService.setHoistedNoteId(node.data.noteId);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("SearchInSubtree", () => {
|
||||
const node = treeService.getActiveNode();
|
||||
|
||||
searchNotesService.searchInSubtree(node.data.noteId);
|
||||
});
|
||||
|
||||
keyboardActionService.setGlobalActionHandler("CopyWithoutFormatting", utils.copySelectionToClipboard);
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -58,13 +58,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
};
|
||||
|
||||
/**
|
||||
* Activates newly created note. Compared to this.activateNote() also refreshes tree.
|
||||
* Activates newly created note. Compared to this.activateNote() also makes sure that frontend has been fully synced.
|
||||
*
|
||||
* @param {string} notePath (or noteId)
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
this.activateNewNote = async notePath => {
|
||||
await treeService.reload();
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
||||
await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
|
||||
};
|
||||
@@ -125,14 +125,14 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes given anonymous function on the server.
|
||||
* Executes given anonymous function on the backend.
|
||||
* Internally this serializes the anonymous function into string and sends it to backend via AJAX.
|
||||
*
|
||||
* @param {string} script - script to be executed on the backend
|
||||
* @param {Array.<?>} params - list of parameters to the anonymous function to be send to backend
|
||||
* @return {Promise<*>} return value of the executed function on the backend
|
||||
*/
|
||||
this.runOnServer = async (script, params = []) => {
|
||||
this.runOnBackend = async (script, params = []) => {
|
||||
if (typeof script === "function") {
|
||||
script = script.toString();
|
||||
}
|
||||
@@ -159,6 +159,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated new name of this API call is runOnBackend so use that
|
||||
* @method
|
||||
*/
|
||||
this.runOnServer = this.runOnBackend;
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "@dateModified =* MONTH AND @log". See full documentation for all options at: https://github.com/zadam/trilium/wiki/Search
|
||||
@@ -290,12 +296,28 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
*/
|
||||
this.createNoteLink = linkService.createNoteLink;
|
||||
|
||||
/**
|
||||
* Adds given text to the editor cursor
|
||||
*
|
||||
* @param {string} text - this must be clear text, HTML is not supported.
|
||||
* @method
|
||||
*/
|
||||
this.addTextToActiveTabEditor = linkService.addTextToEditor;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @returns {NoteFull} active note (loaded into right pane)
|
||||
*/
|
||||
this.getActiveTabNote = noteDetailService.getActiveTabNote;
|
||||
|
||||
/**
|
||||
* See https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editor-Editor.html for a documentation on the returned instance.
|
||||
*
|
||||
* @method
|
||||
* @returns {Editor|null} CKEditor instance or null (e.g. if active note is not a text note)
|
||||
*/
|
||||
this.getActiveTabTextEditor = noteDetailService.getActiveEditor;
|
||||
|
||||
/**
|
||||
* @method
|
||||
* @returns {Promise<string|null>} returns note path of active note or null if there isn't active note
|
||||
@@ -382,6 +404,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, tabConte
|
||||
* @param {function} handler
|
||||
*/
|
||||
this.bindGlobalShortcut = utils.bindGlobalShortcut;
|
||||
|
||||
/**
|
||||
* Trilium runs in backend and frontend process, when something is changed on the backend from script,
|
||||
* frontend will get asynchronously synchronized.
|
||||
*
|
||||
* This method returns a promise which resolves once all the backend -> frontend synchronization is finished.
|
||||
* Typical use case is when new note has been created, we should wait until it is synced into frontend and only then activate it.
|
||||
*
|
||||
* @method
|
||||
*/
|
||||
this.waitUntilSynced = ws.waitForMaxKnownSyncId;
|
||||
}
|
||||
|
||||
export default FrontendScriptApi;
|
||||
117
src/public/javascripts/services/keyboard_actions.js
Normal file
117
src/public/javascripts/services/keyboard_actions.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import server from "./server.js";
|
||||
import utils from "./utils.js";
|
||||
|
||||
const keyboardActionRepo = {};
|
||||
|
||||
const keyboardActionsLoaded = server.get('keyboard-actions').then(actions => {
|
||||
for (const action of actions) {
|
||||
keyboardActionRepo[action.actionName] = action;
|
||||
}
|
||||
});
|
||||
|
||||
server.get('keyboard-shortcuts-for-notes').then(shortcutForNotes => {
|
||||
for (const shortcut in shortcutForNotes) {
|
||||
utils.bindGlobalShortcut(shortcut, async () => {
|
||||
const treeService = (await import("./tree.js")).default;
|
||||
|
||||
treeService.activateNote(shortcutForNotes[shortcut]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function setGlobalActionHandler(actionName, handler) {
|
||||
keyboardActionsLoaded.then(() => {
|
||||
const action = keyboardActionRepo[actionName];
|
||||
|
||||
if (!action) {
|
||||
throw new Error(`Cannot find keyboard action '${actionName}'`);
|
||||
}
|
||||
|
||||
action.handler = handler;
|
||||
|
||||
for (const shortcut of action.effectiveShortcuts) {
|
||||
if (shortcut && !shortcut.startsWith("global:")) { // global shortcuts should be handled in the electron code
|
||||
utils.bindGlobalShortcut(shortcut, handler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setElementActionHandler($el, actionName, handler) {
|
||||
keyboardActionsLoaded.then(() => {
|
||||
const action = keyboardActionRepo[actionName];
|
||||
|
||||
if (!action) {
|
||||
throw new Error(`Cannot find keyboard action '${actionName}'`);
|
||||
}
|
||||
|
||||
// not setting action.handler since this is not global
|
||||
|
||||
for (const shortcut of action.effectiveShortcuts) {
|
||||
if (shortcut) {
|
||||
utils.bindElShortcut($el, shortcut, handler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function triggerAction(actionName) {
|
||||
const action = await getAction(actionName);
|
||||
|
||||
if (!action.handler) {
|
||||
throw new Error(`Action ${actionName} has no handler`);
|
||||
}
|
||||
|
||||
await action.handler();
|
||||
}
|
||||
|
||||
async function getAction(actionName, silent = false) {
|
||||
await keyboardActionsLoaded;
|
||||
|
||||
const action = keyboardActionRepo[actionName];
|
||||
|
||||
if (!action) {
|
||||
if (silent) {
|
||||
console.log(`Cannot find action ${actionName}`);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Cannot find action ${actionName}`);
|
||||
}
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
function updateDisplayedShortcuts($container) {
|
||||
$container.find('kbd[data-kb-action]').each(async (i, el) => {
|
||||
const actionName = $(el).attr('data-kb-action');
|
||||
const action = await getAction(actionName, true);
|
||||
|
||||
if (action) {
|
||||
$(el).text(action.effectiveShortcuts.join(', '));
|
||||
}
|
||||
});
|
||||
|
||||
$container.find('button[data-kb-action],a.icon-action[data-kb-action]').each(async (i, el) => {
|
||||
const actionName = $(el).attr('data-kb-action');
|
||||
const action = await getAction(actionName, true);
|
||||
|
||||
if (action) {
|
||||
const title = $(el).attr('title');
|
||||
const shortcuts = action.effectiveShortcuts.join(', ');
|
||||
const newTitle = !title || !title.trim() ? shortcuts : `${title} (${shortcuts})`;
|
||||
|
||||
$(el).attr('title', newTitle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(() => updateDisplayedShortcuts($(document)));
|
||||
|
||||
export default {
|
||||
setGlobalActionHandler,
|
||||
setElementActionHandler,
|
||||
triggerAction,
|
||||
getAction,
|
||||
updateDisplayedShortcuts
|
||||
};
|
||||
16
src/public/javascripts/services/keys.js
Normal file
16
src/public/javascripts/services/keys.js
Normal file
@@ -0,0 +1,16 @@
|
||||
class Actions {
|
||||
constructor() {
|
||||
this.JUMP_TO = "";
|
||||
}
|
||||
}
|
||||
|
||||
const actions = new Actions();
|
||||
|
||||
function bind() {
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
actions,
|
||||
bind
|
||||
};
|
||||
@@ -6,15 +6,20 @@ import noteDetailService from "./note_detail.js";
|
||||
function getNotePathFromUrl(url) {
|
||||
const notePathMatch = /#(root[A-Za-z0-9/]*)$/.exec(url);
|
||||
|
||||
if (notePathMatch === null) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return notePathMatch[1];
|
||||
}
|
||||
return notePathMatch === null ? null : notePathMatch[1];
|
||||
}
|
||||
|
||||
async function createNoteLink(notePath, noteTitle = null, tooltip = true) {
|
||||
async function createNoteLink(notePath, options = {}) {
|
||||
if (!notePath || !notePath.trim()) {
|
||||
console.error("Missing note path");
|
||||
|
||||
return $("<span>").text("[missing note]");
|
||||
}
|
||||
|
||||
let noteTitle = options.title;
|
||||
const showTooltip = options.showTooltip === undefined ? true : options.showTooltip;
|
||||
const showNotePath = options.showNotePath === undefined ? false : options.showNotePath;
|
||||
|
||||
if (!noteTitle) {
|
||||
const {noteId, parentNoteId} = treeUtils.getNoteIdAndParentIdFromNotePath(notePath);
|
||||
|
||||
@@ -27,30 +32,28 @@ async function createNoteLink(notePath, noteTitle = null, tooltip = true) {
|
||||
}).attr('data-action', 'note')
|
||||
.attr('data-note-path', notePath);
|
||||
|
||||
if (!tooltip) {
|
||||
if (!showTooltip) {
|
||||
$noteLink.addClass("no-tooltip-preview");
|
||||
}
|
||||
|
||||
return $noteLink;
|
||||
}
|
||||
const $container = $("<span>").append($noteLink);
|
||||
|
||||
async function createNoteLinkWithPath(notePath, noteTitle = null) {
|
||||
const $link = await createNoteLink(notePath, noteTitle);
|
||||
if (showNotePath) {
|
||||
notePath = await treeService.resolveNotePath(notePath);
|
||||
|
||||
const $res = $("<span>").append($link);
|
||||
if (notePath) {
|
||||
const noteIds = notePath.split("/");
|
||||
noteIds.pop(); // remove last element
|
||||
|
||||
if (notePath.includes("/")) {
|
||||
const noteIds = notePath.split("/");
|
||||
noteIds.pop(); // remove last element
|
||||
const parentNotePath = noteIds.join("/").trim();
|
||||
|
||||
const parentNotePath = noteIds.join("/").trim();
|
||||
|
||||
if (parentNotePath) {
|
||||
$res.append($("<small>").text(" (" + await treeUtils.getNotePathTitle(parentNotePath) + ")"));
|
||||
if (parentNotePath) {
|
||||
$container.append($("<small>").text(" (" + await treeUtils.getNotePathTitle(parentNotePath) + ")"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
return $container;
|
||||
}
|
||||
|
||||
function getNotePathFromLink($link) {
|
||||
@@ -66,13 +69,16 @@ function getNotePathFromLink($link) {
|
||||
}
|
||||
|
||||
function goToLink(e) {
|
||||
const $link = $(e.target);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const $link = $(e.target).closest("a");
|
||||
|
||||
const notePath = getNotePathFromLink($link);
|
||||
|
||||
if (notePath) {
|
||||
if ((e.which === 1 && e.ctrlKey) || e.which === 2) {
|
||||
noteDetailService.openInTab(notePath);
|
||||
noteDetailService.openInTab(notePath, false);
|
||||
}
|
||||
else if (e.which === 1) {
|
||||
treeService.activateNote(notePath);
|
||||
@@ -89,9 +95,6 @@ function goToLink(e) {
|
||||
}
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -118,7 +121,7 @@ function addTextToEditor(text) {
|
||||
}
|
||||
|
||||
function newTabContextMenu(e) {
|
||||
const $link = $(e.target);
|
||||
const $link = $(e.target).closest("a");
|
||||
|
||||
const notePath = getNotePathFromLink($link);
|
||||
|
||||
@@ -142,22 +145,27 @@ function newTabContextMenu(e) {
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('contextmenu', '.note-detail-text a', newTabContextMenu);
|
||||
$(document).on('contextmenu', "a[data-action='note']", newTabContextMenu);
|
||||
$(document).on('contextmenu', ".note-detail-render a", newTabContextMenu);
|
||||
|
||||
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
|
||||
// of opening the link in new window/tab
|
||||
$(document).on('mousedown', "a[data-action='note']", goToLink);
|
||||
$(document).on('mousedown', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
|
||||
$(document).on('dblclick', '.note-detail-text a', goToLink);
|
||||
$(document).on('mousedown', '.note-detail-text a', function (e) {
|
||||
const notePath = getNotePathFromLink($(e.target));
|
||||
if (notePath && ((e.which === 1 && e.ctrlKey) || e.which === 2)) {
|
||||
const $link = $(e.target).closest("a");
|
||||
const notePath = getNotePathFromLink($link);
|
||||
|
||||
if ((e.which === 1 && e.ctrlKey) || e.which === 2) {
|
||||
// if it's a ctrl-click, then we open on new tab, otherwise normal flow (CKEditor opens link-editing dialog)
|
||||
e.preventDefault();
|
||||
|
||||
noteDetailService.loadNoteDetail(notePath, { newTab: true });
|
||||
if (notePath) {
|
||||
noteDetailService.loadNoteDetail(notePath, {newTab: true});
|
||||
}
|
||||
else {
|
||||
const address = $link.attr('href');
|
||||
|
||||
window.open(address, '_blank');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -166,24 +174,20 @@ $(document).on('mousedown', '.note-detail-text a', function (e) {
|
||||
$(document).on('mousedown', '.note-detail-book a', goToLink);
|
||||
$(document).on('mousedown', '.note-detail-render a', goToLink);
|
||||
$(document).on('mousedown', '.note-detail-text.ck-read-only a', goToLink);
|
||||
$(document).on('mousedown', 'span.ck-button__label', e => {
|
||||
// this is a link preview dialog from CKEditor link editing
|
||||
// for some reason clicked element is span
|
||||
|
||||
const url = $(e.target).text();
|
||||
const notePath = getNotePathFromUrl(url);
|
||||
|
||||
if (notePath) {
|
||||
treeService.activateNote(notePath);
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
$(document).on('mousedown', 'a.ck-link-actions__preview', goToLink);
|
||||
$(document).on('click', 'a.ck-link-actions__preview', e => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(document).on('contextmenu', 'a.ck-link-actions__preview', newTabContextMenu);
|
||||
$(document).on('contextmenu', '.note-detail-text a', newTabContextMenu);
|
||||
$(document).on('contextmenu', "a[data-action='note']", newTabContextMenu);
|
||||
$(document).on('contextmenu', ".note-detail-render a", newTabContextMenu);
|
||||
|
||||
export default {
|
||||
getNotePathFromUrl,
|
||||
createNoteLink,
|
||||
createNoteLinkWithPath,
|
||||
addLinkToEditor,
|
||||
addTextToEditor,
|
||||
goToLink
|
||||
|
||||
@@ -88,7 +88,7 @@ export default class LinkMap {
|
||||
.addClass("note-box")
|
||||
.prop("id", noteBoxId);
|
||||
|
||||
linkService.createNoteLink(noteId, note.title).then($link => {
|
||||
linkService.createNoteLink(noteId, {title: note.title}).then($link => {
|
||||
$link.on('click', e => {
|
||||
try {
|
||||
$link.tooltip('dispose');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import optionsService from "./options.js";
|
||||
|
||||
const MIME_TYPES_DICT = [
|
||||
{ default: true, title: "Plain text", mime: "text/plain" },
|
||||
{ title: "APL", mime: "text/apl" },
|
||||
{ title: "PGP", mime: "application/pgp" },
|
||||
{ title: "ASN.1", mime: "text/x-ttcn-asn" },
|
||||
@@ -91,7 +92,6 @@ const MIME_TYPES_DICT = [
|
||||
{ default: true, title: "Perl", mime: "text/x-perl" },
|
||||
{ default: true, title: "PHP", mime: "text/x-php" },
|
||||
{ title: "Pig", mime: "text/x-pig" },
|
||||
{ title: "Plain Text", mime: "text/plain" },
|
||||
{ title: "PLSQL", mime: "text/x-plsql" },
|
||||
{ title: "PostgreSQL", mime: "text/x-pgsql" },
|
||||
{ title: "PowerShell", mime: "application/x-powershell" },
|
||||
@@ -168,7 +168,7 @@ function loadMimeTypes(options) {
|
||||
|| MIME_TYPES_DICT.filter(mt => mt.default).map(mt => mt.mime);
|
||||
|
||||
for (const mt of mimeTypes) {
|
||||
mt.enabled = enabledMimeTypes.includes(mt.mime);
|
||||
mt.enabled = enabledMimeTypes.includes(mt.mime) || mt.mime === 'text/plain'; // text/plain is always enabled
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
98
src/public/javascripts/services/note_content_renderer.js
Normal file
98
src/public/javascripts/services/note_content_renderer.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import server from "./server.js";
|
||||
import utils from "./utils.js";
|
||||
import renderService from "./render.js";
|
||||
import protectedSessionService from "./protected_session.js";
|
||||
import protectedSessionHolder from "./protected_session_holder.js";
|
||||
|
||||
async function getRenderedContent(note) {
|
||||
const type = getRenderingType(note);
|
||||
|
||||
let $rendered;
|
||||
|
||||
if (type === 'text') {
|
||||
const fullNote = await server.get('notes/' + note.noteId);
|
||||
|
||||
$rendered = $("<div>").html(fullNote.content);
|
||||
}
|
||||
else if (type === 'code') {
|
||||
const fullNote = await server.get('notes/' + note.noteId);
|
||||
|
||||
$rendered = $("<pre>").text(fullNote.content);
|
||||
}
|
||||
else if (type === 'image') {
|
||||
$rendered = $("<img>").attr("src", `api/images/${note.noteId}/${note.title}`);
|
||||
}
|
||||
else if (type === 'file') {
|
||||
function getFileUrl() {
|
||||
return utils.getUrlForDownload("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.on('click', () => utils.download(getFileUrl()));
|
||||
$openButton.on('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);
|
||||
|
||||
$rendered = $('<div>')
|
||||
.append($downloadButton)
|
||||
.append(' ')
|
||||
.append($openButton);
|
||||
}
|
||||
else if (type === 'render') {
|
||||
$rendered = $('<div>');
|
||||
|
||||
await renderService.render(note, $rendered, this.ctx);
|
||||
}
|
||||
else if (type === 'protected-session') {
|
||||
const $button = $(`<button class="btn btn-sm"><span class="bx bx-log-in"></span> Enter protected session</button>`)
|
||||
.on('click', protectedSessionService.enterProtectedSession);
|
||||
|
||||
$rendered = $("<div>")
|
||||
.append("<div>This note is protected and to access it you need to enter password.</div>")
|
||||
.append("<br/>")
|
||||
.append($button);
|
||||
}
|
||||
else {
|
||||
$rendered = $("<em>Content of this note cannot be displayed in the book format</em>");
|
||||
}
|
||||
|
||||
if (note.cssClass) {
|
||||
$rendered.addClass(note.cssClass);
|
||||
}
|
||||
|
||||
return {
|
||||
renderedContent: $rendered,
|
||||
type
|
||||
};
|
||||
}
|
||||
|
||||
function getRenderingType(note) {
|
||||
let type = note.type;
|
||||
|
||||
if (note.isProtected) {
|
||||
if (protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||
protectedSessionHolder.touchProtectedSession();
|
||||
}
|
||||
else {
|
||||
type = 'protected-session';
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
export default {
|
||||
getRenderedContent
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import utils from "./utils.js";
|
||||
import contextMenuService from "./context_menu.js";
|
||||
import treeUtils from "./tree_utils.js";
|
||||
import tabRow from "./tab_row.js";
|
||||
import keyboardActionService from "./keyboard_actions.js";
|
||||
|
||||
const $tabContentsContainer = $("#note-tab-container");
|
||||
const $savedIndicator = $(".saved-indicator");
|
||||
@@ -34,8 +35,8 @@ async function reloadAllTabs() {
|
||||
}
|
||||
}
|
||||
|
||||
async function openInTab(notePath) {
|
||||
await loadNoteDetail(notePath, { newTab: true });
|
||||
async function openInTab(notePath, activate) {
|
||||
await loadNoteDetail(notePath, { newTab: true, activate });
|
||||
}
|
||||
|
||||
async function switchToNote(notePath) {
|
||||
@@ -173,7 +174,11 @@ async function showTab(tabId) {
|
||||
if (newActiveTabContext && newActiveTabContext.notePath) {
|
||||
const newActiveNode = await treeService.getNodeFromPath(newActiveTabContext.notePath);
|
||||
|
||||
if (newActiveNode && newActiveNode.isVisible()) {
|
||||
if (newActiveNode) {
|
||||
if (!newActiveNode.isVisible()) {
|
||||
await treeService.expandToNote(newActiveTabContext.notePath);
|
||||
}
|
||||
|
||||
newActiveNode.setActive(true, {noEvents: true});
|
||||
}
|
||||
}
|
||||
@@ -196,17 +201,13 @@ async function loadNoteDetail(origNotePath, options = {}) {
|
||||
const newTab = !!options.newTab;
|
||||
const activate = !!options.activate;
|
||||
|
||||
const notePath = await treeService.resolveNotePath(origNotePath);
|
||||
let notePath = await treeService.resolveNotePath(origNotePath);
|
||||
|
||||
if (!notePath) {
|
||||
console.error(`Cannot resolve note path ${origNotePath}`);
|
||||
|
||||
// fallback to display something
|
||||
if (tabContexts.length === 0) {
|
||||
await openEmptyTab();
|
||||
}
|
||||
|
||||
return;
|
||||
notePath = 'root';
|
||||
}
|
||||
|
||||
const noteId = treeUtils.getNoteIdFromNotePath(notePath);
|
||||
@@ -273,7 +274,9 @@ async function filterTabs(noteId) {
|
||||
|
||||
async function noteDeleted(noteId) {
|
||||
for (const tc of tabContexts) {
|
||||
if (tc.notePath && tc.notePath.split("/").includes(noteId)) {
|
||||
// not removing active even if it contains deleted note since that one will move to another note (handled by deletion logic)
|
||||
// and we would lose tab context state (e.g. sidebar visibility)
|
||||
if (!tc.isActive() && tc.notePath && tc.notePath.split("/").includes(noteId)) {
|
||||
await tabRow.removeTab(tc.$tab[0]);
|
||||
}
|
||||
}
|
||||
@@ -419,33 +422,31 @@ $(tabRow.el).on('contextmenu', '.note-tab', e => {
|
||||
});
|
||||
});
|
||||
|
||||
if (utils.isElectron()) {
|
||||
utils.bindGlobalShortcut('ctrl+t', () => {
|
||||
openEmptyTab();
|
||||
});
|
||||
keyboardActionService.setGlobalActionHandler('OpenNewTab', () => {
|
||||
openEmptyTab();
|
||||
});
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+w', () => {
|
||||
if (tabRow.activeTabEl) {
|
||||
tabRow.removeTab(tabRow.activeTabEl);
|
||||
}
|
||||
});
|
||||
keyboardActionService.setGlobalActionHandler('CloseActiveTab', () => {
|
||||
if (tabRow.activeTabEl) {
|
||||
tabRow.removeTab(tabRow.activeTabEl);
|
||||
}
|
||||
});
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+tab', () => {
|
||||
const nextTab = tabRow.nextTabEl;
|
||||
keyboardActionService.setGlobalActionHandler('ActivateNextTab', () => {
|
||||
const nextTab = tabRow.nextTabEl;
|
||||
|
||||
if (nextTab) {
|
||||
tabRow.activateTab(nextTab);
|
||||
}
|
||||
});
|
||||
if (nextTab) {
|
||||
tabRow.activateTab(nextTab);
|
||||
}
|
||||
});
|
||||
|
||||
utils.bindGlobalShortcut('ctrl+shift+tab', () => {
|
||||
const prevTab = tabRow.previousTabEl;
|
||||
keyboardActionService.setGlobalActionHandler('ActivatePreviousTab', () => {
|
||||
const prevTab = tabRow.previousTabEl;
|
||||
|
||||
if (prevTab) {
|
||||
tabRow.activateTab(prevTab);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (prevTab) {
|
||||
tabRow.activateTab(prevTab);
|
||||
}
|
||||
});
|
||||
|
||||
tabRow.addListener('activeTabChange', openTabsChanged);
|
||||
tabRow.addListener('tabRemove', openTabsChanged);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
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";
|
||||
import noteContentRenderer from "./note_content_renderer.js";
|
||||
|
||||
const MIN_ZOOM_LEVEL = 1;
|
||||
const MAX_ZOOM_LEVEL = 6;
|
||||
@@ -47,6 +43,7 @@ class NoteDetailBook {
|
||||
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.$help = this.$component.find('.note-detail-book-help');
|
||||
|
||||
this.$zoomInButton.on('click', () => this.setZoom(this.zoomLevel - 1));
|
||||
this.$zoomOutButton.on('click', () => this.setZoom(this.zoomLevel + 1));
|
||||
@@ -109,6 +106,7 @@ class NoteDetailBook {
|
||||
|
||||
async render() {
|
||||
this.$content.empty();
|
||||
this.$help.hide();
|
||||
|
||||
if (this.isAutoBook()) {
|
||||
const $addTextLink = $('<a href="javascript:">here</a>').on('click', () => {
|
||||
@@ -128,19 +126,21 @@ class NoteDetailBook {
|
||||
}
|
||||
|
||||
async renderIntoElement(note, $container) {
|
||||
for (const childNote of await note.getChildNotes()) {
|
||||
const type = this.getRenderingType(childNote);
|
||||
const childNotes = await note.getChildNotes();
|
||||
|
||||
for (const childNote of childNotes) {
|
||||
const childNotePath = this.ctx.notePath + '/' + childNote.noteId;
|
||||
|
||||
const {type, renderedContent} = await noteContentRenderer.getRenderedContent(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(childNotePath, null, false)))
|
||||
.append($('<h5 class="note-book-title">').append(await linkService.createNoteLink(childNotePath, {showTooltip: false})))
|
||||
.append($('<div class="note-book-content">')
|
||||
.css("max-height", ZOOMS[this.zoomLevel].height)
|
||||
.append(await this.getNoteContent(type, childNote)));
|
||||
.append(renderedContent));
|
||||
|
||||
const childCount = childNote.getChildNoteIds().length;
|
||||
|
||||
@@ -148,87 +148,17 @@ class NoteDetailBook {
|
||||
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($(`<a class="note-book-open-children-button no-print" href="javascript:">+ Show ${label}</a>`))
|
||||
.append($(`<a class="note-book-hide-children-button no-print" 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() {
|
||||
return utils.getUrlForDownload("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.on('click', () => utils.download(getFileUrl()));
|
||||
$openButton.on('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="bx bx-log-in"></span> Enter protected session</button>`)
|
||||
.on('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>";
|
||||
if (childNotes.length === 0) {
|
||||
this.$help.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,21 +186,6 @@ class NoteDetailBook {
|
||||
}
|
||||
}
|
||||
|
||||
getRenderingType(childNote) {
|
||||
let type = childNote.type;
|
||||
|
||||
if (childNote.isProtected) {
|
||||
if (protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||
protectedSessionHolder.touchProtectedSession();
|
||||
}
|
||||
else {
|
||||
type = 'protected-session';
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
getContent() {
|
||||
// for auto-book cases when renaming title there should be content
|
||||
return "";
|
||||
|
||||
@@ -3,7 +3,7 @@ import bundleService from "./bundle.js";
|
||||
import toastService from "./toast.js";
|
||||
import server from "./server.js";
|
||||
import noteDetailService from "./note_detail.js";
|
||||
import utils from "./utils.js";
|
||||
import keyboardActionService from "./keyboard_actions.js";
|
||||
|
||||
class NoteDetailCode {
|
||||
|
||||
@@ -17,7 +17,7 @@ class NoteDetailCode {
|
||||
this.$editorEl = this.$component.find('.note-detail-code-editor');
|
||||
this.$executeScriptButton = ctx.$tabContent.find(".execute-script-button");
|
||||
|
||||
utils.bindElShortcut(ctx.$tabContent, "ctrl+return", () => this.executeCurrentNote());
|
||||
keyboardActionService.setElementActionHandler(ctx.$tabContent, 'RunActiveNote', () => this.executeCurrentNote());
|
||||
|
||||
this.$executeScriptButton.on('click', () => this.executeCurrentNote());
|
||||
}
|
||||
@@ -55,18 +55,21 @@ class NoteDetailCode {
|
||||
this.onNoteChange(() => this.ctx.noteChanged());
|
||||
}
|
||||
|
||||
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
|
||||
// we provide fallback
|
||||
this.codeEditor.setValue(this.ctx.note.content || "");
|
||||
// lazy loading above can take time and tab might have been already switched to another note
|
||||
if (this.ctx.note && this.ctx.note.type === 'code') {
|
||||
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
|
||||
// we provide fallback
|
||||
this.codeEditor.setValue(this.ctx.note.content || "");
|
||||
|
||||
const info = CodeMirror.findModeByMIME(this.ctx.note.mime);
|
||||
const info = CodeMirror.findModeByMIME(this.ctx.note.mime);
|
||||
|
||||
if (info) {
|
||||
this.codeEditor.setOption("mode", info.mime);
|
||||
CodeMirror.autoLoadMode(this.codeEditor, info.mode);
|
||||
if (info) {
|
||||
this.codeEditor.setOption("mode", info.mime);
|
||||
CodeMirror.autoLoadMode(this.codeEditor, info.mode);
|
||||
}
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
show() {
|
||||
|
||||
@@ -39,8 +39,11 @@ class NoteDetailFile {
|
||||
});
|
||||
|
||||
this.$uploadNewRevisionInput.on('change', async () => {
|
||||
const fileToUpload = this.$uploadNewRevisionInput[0].files[0]; // copy to allow reset below
|
||||
this.$uploadNewRevisionInput.val('');
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('upload', this.$uploadNewRevisionInput[0].files[0]);
|
||||
formData.append('upload', fileToUpload);
|
||||
|
||||
const result = await $.ajax({
|
||||
url: baseApiUrl + 'notes/' + this.ctx.note.noteId + '/file',
|
||||
|
||||
@@ -48,8 +48,11 @@ class NoteDetailImage {
|
||||
});
|
||||
|
||||
this.$uploadNewRevisionInput.on('change', async () => {
|
||||
const fileToUpload = this.$uploadNewRevisionInput[0].files[0]; // copy to allow reset below
|
||||
this.$uploadNewRevisionInput.val('');
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('upload', this.$uploadNewRevisionInput[0].files[0]);
|
||||
formData.append('upload', fileToUpload);
|
||||
|
||||
const result = await $.ajax({
|
||||
url: baseApiUrl + 'images/' + this.ctx.note.noteId,
|
||||
|
||||
@@ -129,9 +129,10 @@ class NoteDetailRelationMap {
|
||||
return;
|
||||
}
|
||||
|
||||
const {note} = await server.post(`notes/${this.ctx.note.noteId}/children`, {
|
||||
const {note} = await server.post(`notes/${this.ctx.note.noteId}/children?target=into`, {
|
||||
title,
|
||||
target: 'into'
|
||||
content: '',
|
||||
type: 'text'
|
||||
});
|
||||
|
||||
toastService.showMessage("Click on canvas to place new note");
|
||||
@@ -159,7 +160,7 @@ class NoteDetailRelationMap {
|
||||
const noteId = this.idToNoteId($noteBox.prop("id"));
|
||||
|
||||
if (cmd === "open-in-new-tab") {
|
||||
noteDetailService.openInTab(noteId);
|
||||
noteDetailService.openInTab(noteId, false);
|
||||
}
|
||||
else if (cmd === "remove") {
|
||||
const confirmDialog = await import('../dialogs/confirm.js');
|
||||
@@ -238,14 +239,17 @@ class NoteDetailRelationMap {
|
||||
|
||||
await libraryLoader.requireLibrary(libraryLoader.RELATION_MAP);
|
||||
|
||||
this.loadMapData();
|
||||
|
||||
jsPlumb.ready(() => {
|
||||
this.initJsPlumbInstance();
|
||||
// lazy loading above can take time and tab might have been already switched to another note
|
||||
if (this.ctx.note && this.ctx.note.type === 'relation-map') {
|
||||
this.loadMapData();
|
||||
|
||||
this.initPanZoom();
|
||||
this.initJsPlumbInstance();
|
||||
|
||||
this.loadNotesAndRelations();
|
||||
this.initPanZoom();
|
||||
|
||||
this.loadNotesAndRelations();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
@@ -490,7 +494,7 @@ class NoteDetailRelationMap {
|
||||
}
|
||||
|
||||
async createNoteBox(noteId, title, x, y) {
|
||||
const $link = await linkService.createNoteLink(noteId, title);
|
||||
const $link = await linkService.createNoteLink(noteId, {title});
|
||||
$link.mousedown(e => {
|
||||
console.log(e);
|
||||
|
||||
|
||||
@@ -1,6 +1,43 @@
|
||||
import libraryLoader from "./library_loader.js";
|
||||
import treeService from './tree.js';
|
||||
import noteAutocompleteService from './note_autocomplete.js';
|
||||
import mimeTypesService from './mime_types.js';
|
||||
|
||||
const ENABLE_INSPECTOR = false;
|
||||
|
||||
const mentionSetup = {
|
||||
feeds: [
|
||||
{
|
||||
marker: '@',
|
||||
feed: queryText => {
|
||||
return new Promise((res, rej) => {
|
||||
noteAutocompleteService.autocompleteSource(queryText, rows => {
|
||||
if (rows.length === 1 && rows[0].title === 'No results') {
|
||||
rows = [];
|
||||
}
|
||||
|
||||
for (const row of rows) {
|
||||
row.text = row.name = row.noteTitle;
|
||||
row.id = '@' + row.text;
|
||||
row.link = '#' + row.path;
|
||||
}
|
||||
|
||||
res(rows);
|
||||
});
|
||||
});
|
||||
},
|
||||
itemRenderer: item => {
|
||||
const itemElement = document.createElement('span');
|
||||
|
||||
itemElement.classList.add('mentions-item');
|
||||
itemElement.innerHTML = `${item.highlightedTitle} `;
|
||||
|
||||
return itemElement;
|
||||
},
|
||||
minimumCharacters: 0
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
class NoteDetailText {
|
||||
/**
|
||||
@@ -10,6 +47,7 @@ class NoteDetailText {
|
||||
this.ctx = ctx;
|
||||
this.$component = ctx.$tabContent.find('.note-detail-text');
|
||||
this.$editorEl = this.$component.find('.note-detail-text-editor');
|
||||
this.textEditorPromise = null;
|
||||
this.textEditor = null;
|
||||
|
||||
this.$component.on("dblclick", "img", e => {
|
||||
@@ -26,81 +64,76 @@ class NoteDetailText {
|
||||
else {
|
||||
window.open(src, '_blank');
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async render() {
|
||||
if (!this.textEditor) {
|
||||
await libraryLoader.requireLibrary(libraryLoader.CKEDITOR);
|
||||
if (!this.textEditorPromise) {
|
||||
this.textEditorPromise = this.initEditor();
|
||||
}
|
||||
|
||||
await this.textEditorPromise;
|
||||
|
||||
// lazy loading above can take time and tab might have been already switched to another note
|
||||
if (this.ctx.note && this.ctx.note.type === 'text') {
|
||||
this.textEditor.isReadOnly = await this.isReadOnly();
|
||||
|
||||
// CKEditor since version 12 needs the element to be visible before initialization. At the same time
|
||||
// we want to avoid flicker - i.e. show editor only once everything is ready. That's why we have separate
|
||||
// display of $component in both branches.
|
||||
this.$component.show();
|
||||
|
||||
// textEditor might have been initialized during previous await so checking again
|
||||
// looks like double initialization can freeze CKEditor pretty badly
|
||||
if (!this.textEditor) {
|
||||
this.textEditor = await BalloonEditor.create(this.$editorEl[0], {
|
||||
placeholder: "Type the content of your note here ...",
|
||||
mention: {
|
||||
feeds: [
|
||||
{
|
||||
marker: '@',
|
||||
feed: queryText => {
|
||||
return new Promise((res, rej) => {
|
||||
noteAutocompleteService.autocompleteSource(queryText, rows => {
|
||||
if (rows.length === 1 && rows[0].title === 'No results') {
|
||||
rows = [];
|
||||
}
|
||||
this.textEditor.setData(this.ctx.note.content);
|
||||
}
|
||||
}
|
||||
|
||||
for (const row of rows) {
|
||||
row.text = row.name = row.noteTitle;
|
||||
row.id = '@' + row.text;
|
||||
row.link = '#' + row.path;
|
||||
}
|
||||
async initEditor() {
|
||||
await libraryLoader.requireLibrary(libraryLoader.CKEDITOR);
|
||||
|
||||
console.log(rows.slice(0, Math.min(5, rows.length)));
|
||||
|
||||
res(rows);
|
||||
});
|
||||
});
|
||||
},
|
||||
itemRenderer: item => {
|
||||
const itemElement = document.createElement('span');
|
||||
|
||||
itemElement.classList.add('mentions-item');
|
||||
itemElement.innerHTML = `${item.highlightedTitle} `;
|
||||
|
||||
return itemElement;
|
||||
},
|
||||
minimumCharacters: 0
|
||||
}
|
||||
]
|
||||
const codeBlockLanguages =
|
||||
(await mimeTypesService.getMimeTypes())
|
||||
.filter(mt => mt.enabled)
|
||||
.map(mt => {
|
||||
return {
|
||||
language: mt.mime.toLowerCase().replace(/[\W_]+/g,"-"),
|
||||
label: mt.title
|
||||
}
|
||||
});
|
||||
|
||||
this.onNoteChange(() => this.ctx.noteChanged());
|
||||
}
|
||||
}
|
||||
|
||||
this.textEditor.isReadOnly = await this.isReadOnly();
|
||||
|
||||
// CKEditor since version 12 needs the element to be visible before initialization. At the same time
|
||||
// we want to avoid flicker - i.e. show editor only once everything is ready. That's why we have separate
|
||||
// display of $component in both branches.
|
||||
this.$component.show();
|
||||
|
||||
this.textEditor.setData(this.ctx.note.content);
|
||||
const textEditorInstance = await BalloonEditor.create(this.$editorEl[0], {
|
||||
placeholder: "Type the content of your note here ...",
|
||||
mention: mentionSetup,
|
||||
codeBlock: {
|
||||
languages: codeBlockLanguages
|
||||
}
|
||||
});
|
||||
|
||||
if (glob.isDev && ENABLE_INSPECTOR) {
|
||||
await import('../../libraries/ckeditor/inspector.js');
|
||||
CKEditorInspector.attach(textEditorInstance);
|
||||
}
|
||||
|
||||
this.textEditor = textEditorInstance;
|
||||
|
||||
this.onNoteChange(() => this.ctx.noteChanged());
|
||||
}
|
||||
|
||||
getContent() {
|
||||
let content = this.textEditor.getData();
|
||||
const content = this.textEditor.getData();
|
||||
|
||||
// if content is only tags/whitespace (typically <p> </p>), then just make it empty
|
||||
// this is important when setting new note to code
|
||||
if (jQuery(content).text().trim() === '' && !content.includes("<img")) {
|
||||
content = '';
|
||||
}
|
||||
return this.isContentEmpty(content) ? '' : content;
|
||||
}
|
||||
|
||||
return content;
|
||||
isContentEmpty(content) {
|
||||
content = content.toLowerCase();
|
||||
|
||||
return jQuery(content).text().trim() === ''
|
||||
&& !content.includes("<img")
|
||||
&& !content.includes("<section")
|
||||
}
|
||||
|
||||
async isReadOnly() {
|
||||
|
||||
@@ -13,6 +13,10 @@ class Options {
|
||||
return this.arr[key];
|
||||
}
|
||||
|
||||
getNames() {
|
||||
return Object.keys(this.arr);
|
||||
}
|
||||
|
||||
getJson(key) {
|
||||
try {
|
||||
return JSON.parse(this.arr[key]);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user