mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 17:26:38 +01:00
Compare commits
29 Commits
v0.42.0-be
...
v0.42.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37da0adb8a | ||
|
|
4f50864ec8 | ||
|
|
30b9ef8604 | ||
|
|
b063b4c528 | ||
|
|
e08b0141a4 | ||
|
|
9d8b8e26a1 | ||
|
|
cb70109ee7 | ||
|
|
e541abbd60 | ||
|
|
940a70adc5 | ||
|
|
88e8eb7e9c | ||
|
|
b365c186a1 | ||
|
|
64c9734f05 | ||
|
|
48c843c087 | ||
|
|
0e4eec10b9 | ||
|
|
a3661cb763 | ||
|
|
115879ec4a | ||
|
|
df11b076bc | ||
|
|
54ecd2ee75 | ||
|
|
2369bcf9fc | ||
|
|
5d8808a2ad | ||
|
|
62b993f06f | ||
|
|
8aa5608085 | ||
|
|
b452d7e5c5 | ||
|
|
9b9d6d86d0 | ||
|
|
7f2755d4a0 | ||
|
|
3b268cc8eb | ||
|
|
6dfe335707 | ||
|
|
c7125d2b50 | ||
|
|
e8a33a5ee7 |
18
.idea/dataSources.xml
generated
18
.idea/dataSources.xml
generated
@@ -1,25 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="document.db" uuid="a2c75661-f9e2-478f-a69f-6a9409e69997">
|
||||
<data-source source="LOCAL" name="SQLite - document.db" uuid="d0fd879f-1e1d-4d5c-9c21-0e5cf9ab2976">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$USER_HOME$/trilium-data/document.db</jdbc-url>
|
||||
</data-source>
|
||||
<data-source source="LOCAL" name="document" uuid="066dc5f4-4097-429e-8cf1-3adc0a9d648a">
|
||||
<driver-ref>sqlite.xerial</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/dist/trilium linux x64/trilium-data/document.db</jdbc-url>
|
||||
<libraries>
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/xerial-sqlite-license.txt</url>
|
||||
</library>
|
||||
<library>
|
||||
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.16.1/sqlite-jdbc-3.16.1.jar</url>
|
||||
</library>
|
||||
</libraries>
|
||||
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,692 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dataSource name="document.db">
|
||||
<database-model serializer="dbm" dbms="SQLITE" family-id="SQLITE" format-version="4.18">
|
||||
<root id="1">
|
||||
<ServerVersion>3.16.1</ServerVersion>
|
||||
</root>
|
||||
<schema id="2" parent="1" name="main">
|
||||
<Current>1</Current>
|
||||
</schema>
|
||||
<collation id="3" parent="1" name="BINARY"/>
|
||||
<collation id="4" parent="1" name="NOCASE"/>
|
||||
<collation id="5" parent="1" name="RTRIM"/>
|
||||
<table id="6" parent="2" name="api_tokens"/>
|
||||
<table id="7" parent="2" name="attributes"/>
|
||||
<table id="8" parent="2" name="branches"/>
|
||||
<table id="9" parent="2" name="note_contents"/>
|
||||
<table id="10" parent="2" name="note_revision_contents"/>
|
||||
<table id="11" parent="2" name="note_revisions"/>
|
||||
<table id="12" parent="2" name="notes"/>
|
||||
<table id="13" parent="2" name="options"/>
|
||||
<table id="14" parent="2" name="recent_notes"/>
|
||||
<table id="15" parent="2" name="source_ids"/>
|
||||
<table id="16" parent="2" name="sqlite_master">
|
||||
<System>1</System>
|
||||
</table>
|
||||
<table id="17" parent="2" name="sqlite_sequence">
|
||||
<System>1</System>
|
||||
</table>
|
||||
<table id="18" parent="2" name="sync"/>
|
||||
<column id="19" parent="6" name="apiTokenId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="20" parent="6" name="token">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="21" parent="6" name="utcDateCreated">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="22" parent="6" name="isDeleted">
|
||||
<Position>4</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="23" parent="6" name="hash">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>apiTokenId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="25" parent="6">
|
||||
<ColNames>apiTokenId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_api_tokens_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="26" parent="7" name="attributeId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="27" parent="7" name="noteId">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="28" parent="7" name="type">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="29" parent="7" name="name">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="30" parent="7" name="value">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>''</DefaultExpression>
|
||||
</column>
|
||||
<column id="31" parent="7" name="position">
|
||||
<Position>6</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="32" parent="7" name="utcDateCreated">
|
||||
<Position>7</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="33" parent="7" name="utcDateModified">
|
||||
<Position>8</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="34" parent="7" name="isDeleted">
|
||||
<Position>9</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<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="37" parent="7" name="isInheritable">
|
||||
<Position>12</Position>
|
||||
<DataType>int|0s</DataType>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<index id="38" parent="7" name="sqlite_autoindex_attributes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>attributeId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="39" parent="7" name="IDX_attributes_noteId_index">
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="40" parent="7" name="IDX_attributes_name_value">
|
||||
<ColNames>name
|
||||
value</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="41" parent="7" name="IDX_attributes_value_index">
|
||||
<ColNames>value</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="42" parent="7">
|
||||
<ColNames>attributeId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_attributes_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="43" parent="8" name="branchId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="44" parent="8" name="noteId">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="45" parent="8" name="parentNoteId">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="46" parent="8" name="notePosition">
|
||||
<Position>4</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="47" parent="8" name="prefix">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
</column>
|
||||
<column id="48" parent="8" name="isExpanded">
|
||||
<Position>6</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="49" parent="8" name="isDeleted">
|
||||
<Position>7</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="50" parent="8" name="deleteId">
|
||||
<Position>8</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<DefaultExpression>NULL</DefaultExpression>
|
||||
</column>
|
||||
<column id="51" parent="8" name="utcDateModified">
|
||||
<Position>9</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<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="54" parent="8" name="sqlite_autoindex_branches_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>branchId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="55" parent="8" name="IDX_branches_noteId_parentNoteId">
|
||||
<ColNames>noteId
|
||||
parentNoteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="56" parent="8" name="IDX_branches_parentNoteId">
|
||||
<ColNames>parentNoteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="57" parent="8">
|
||||
<ColNames>branchId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_branches_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="58" parent="9" name="noteId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="59" parent="9" name="content">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<DefaultExpression>NULL</DefaultExpression>
|
||||
</column>
|
||||
<column id="60" parent="9" name="hash">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="61" parent="9" name="utcDateModified">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="62" parent="9" name="sqlite_autoindex_note_contents_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="63" parent="9">
|
||||
<ColNames>noteId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_note_contents_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="64" parent="10" name="noteRevisionId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="65" parent="10" name="content">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
</column>
|
||||
<column id="66" parent="10" name="hash">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>''</DefaultExpression>
|
||||
</column>
|
||||
<column id="67" parent="10" name="utcDateModified">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="68" parent="10" name="sqlite_autoindex_note_revision_contents_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="69" parent="10">
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_note_revision_contents_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="70" parent="11" name="noteRevisionId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="71" parent="11" name="noteId">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="72" parent="11" name="title">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
</column>
|
||||
<column id="73" parent="11" name="contentLength">
|
||||
<Position>4</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="74" parent="11" name="isErased">
|
||||
<Position>5</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="75" parent="11" name="isProtected">
|
||||
<Position>6</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="76" parent="11" name="utcDateLastEdited">
|
||||
<Position>7</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="77" parent="11" name="utcDateCreated">
|
||||
<Position>8</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="78" parent="11" name="utcDateModified">
|
||||
<Position>9</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="79" parent="11" name="dateLastEdited">
|
||||
<Position>10</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="80" parent="11" name="dateCreated">
|
||||
<Position>11</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="81" parent="11" name="type">
|
||||
<Position>12</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>''</DefaultExpression>
|
||||
</column>
|
||||
<column id="82" parent="11" name="mime">
|
||||
<Position>13</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>''</DefaultExpression>
|
||||
</column>
|
||||
<column id="83" parent="11" name="hash">
|
||||
<Position>14</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>''</DefaultExpression>
|
||||
</column>
|
||||
<index id="84" parent="11" name="sqlite_autoindex_note_revisions_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="85" parent="11" name="IDX_note_revisions_noteId">
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="86" parent="11" name="IDX_note_revisions_utcDateLastEdited">
|
||||
<ColNames>utcDateLastEdited</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="87" parent="11" name="IDX_note_revisions_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="88" parent="11" name="IDX_note_revisions_dateLastEdited">
|
||||
<ColNames>dateLastEdited</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="89" parent="11" name="IDX_note_revisions_dateCreated">
|
||||
<ColNames>dateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="90" parent="11">
|
||||
<ColNames>noteRevisionId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_note_revisions_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="91" parent="12" name="noteId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="92" parent="12" name="title">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>"note"</DefaultExpression>
|
||||
</column>
|
||||
<column id="93" parent="12" name="contentLength">
|
||||
<Position>3</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="94" parent="12" name="isProtected">
|
||||
<Position>4</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="95" parent="12" name="type">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>'text'</DefaultExpression>
|
||||
</column>
|
||||
<column id="96" parent="12" name="mime">
|
||||
<Position>6</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>'text/html'</DefaultExpression>
|
||||
</column>
|
||||
<column id="97" parent="12" name="hash">
|
||||
<Position>7</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="98" parent="12" name="isDeleted">
|
||||
<Position>8</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<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="101" parent="12" name="dateCreated">
|
||||
<Position>11</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="102" parent="12" name="dateModified">
|
||||
<Position>12</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="103" parent="12" name="utcDateCreated">
|
||||
<Position>13</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<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>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="106" parent="12" name="IDX_notes_title">
|
||||
<ColNames>title</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="107" parent="12" name="IDX_notes_type">
|
||||
<ColNames>type</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="108" parent="12" name="IDX_notes_isDeleted">
|
||||
<ColNames>isDeleted</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="109" parent="12" name="IDX_notes_dateCreated">
|
||||
<ColNames>dateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="110" parent="12" name="IDX_notes_dateModified">
|
||||
<ColNames>dateModified</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="111" parent="12" name="IDX_notes_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<index id="112" parent="12" name="IDX_notes_utcDateModified">
|
||||
<ColNames>utcDateModified</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="113" parent="12">
|
||||
<ColNames>noteId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_notes_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="114" parent="13" name="name">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="115" parent="13" name="value">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
</column>
|
||||
<column id="116" parent="13" name="isSynced">
|
||||
<Position>3</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="117" parent="13" name="hash">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="118" parent="13" name="utcDateCreated">
|
||||
<Position>5</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="119" parent="13" name="utcDateModified">
|
||||
<Position>6</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="120" parent="13" name="sqlite_autoindex_options_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>name</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="121" parent="13">
|
||||
<ColNames>name</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_options_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="122" parent="14" name="noteId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="123" parent="14" name="notePath">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="124" parent="14" name="hash">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>""</DefaultExpression>
|
||||
</column>
|
||||
<column id="125" parent="14" name="utcDateCreated">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="126" parent="14" name="isDeleted">
|
||||
<Position>5</Position>
|
||||
<DataType>INT|0s</DataType>
|
||||
</column>
|
||||
<index id="127" parent="14" name="sqlite_autoindex_recent_notes_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>noteId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<key id="128" parent="14">
|
||||
<ColNames>noteId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_recent_notes_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="129" parent="15" name="sourceId">
|
||||
<Position>1</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="130" parent="15" name="utcDateCreated">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="131" parent="15" name="sqlite_autoindex_source_ids_1">
|
||||
<NameSurrogate>1</NameSurrogate>
|
||||
<ColNames>sourceId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="132" parent="15" name="IDX_source_ids_utcDateCreated">
|
||||
<ColNames>utcDateCreated</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="133" parent="15">
|
||||
<ColNames>sourceId</ColNames>
|
||||
<Primary>1</Primary>
|
||||
<UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName>
|
||||
</key>
|
||||
<column id="134" parent="16" name="type">
|
||||
<Position>1</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="135" parent="16" name="name">
|
||||
<Position>2</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="136" parent="16" name="tbl_name">
|
||||
<Position>3</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="137" parent="16" name="rootpage">
|
||||
<Position>4</Position>
|
||||
<DataType>integer|0s</DataType>
|
||||
</column>
|
||||
<column id="138" parent="16" name="sql">
|
||||
<Position>5</Position>
|
||||
<DataType>text|0s</DataType>
|
||||
</column>
|
||||
<column id="139" parent="17" name="name">
|
||||
<Position>1</Position>
|
||||
</column>
|
||||
<column id="140" parent="17" name="seq">
|
||||
<Position>2</Position>
|
||||
</column>
|
||||
<column id="141" parent="18" name="id">
|
||||
<Position>1</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<SequenceIdentity>1</SequenceIdentity>
|
||||
</column>
|
||||
<column id="142" parent="18" name="entityName">
|
||||
<Position>2</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="143" parent="18" name="entityId">
|
||||
<Position>3</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="144" parent="18" name="sourceId">
|
||||
<Position>4</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<column id="145" parent="18" name="isSynced">
|
||||
<Position>5</Position>
|
||||
<DataType>INTEGER|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
<DefaultExpression>0</DefaultExpression>
|
||||
</column>
|
||||
<column id="146" parent="18" name="utcSyncDate">
|
||||
<Position>6</Position>
|
||||
<DataType>TEXT|0s</DataType>
|
||||
<NotNull>1</NotNull>
|
||||
</column>
|
||||
<index id="147" parent="18" name="IDX_sync_entityName_entityId">
|
||||
<ColNames>entityName
|
||||
entityId</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
<Unique>1</Unique>
|
||||
</index>
|
||||
<index id="148" parent="18" name="IDX_sync_utcSyncDate">
|
||||
<ColNames>utcSyncDate</ColNames>
|
||||
<ColumnCollations></ColumnCollations>
|
||||
</index>
|
||||
<key id="149" parent="18">
|
||||
<ColNames>id</ColNames>
|
||||
<Primary>1</Primary>
|
||||
</key>
|
||||
</database-model>
|
||||
</dataSource>
|
||||
@@ -1,2 +0,0 @@
|
||||
#n:main
|
||||
!<md> [0, 0, null, null, -2147483648, -2147483648]
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:12.16.2-alpine
|
||||
FROM node:12.16.3-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.16.2
|
||||
NODE_VERSION=12.16.3
|
||||
|
||||
if [ "$1" != "DONTCOPY" ]
|
||||
then
|
||||
|
||||
@@ -34,4 +34,5 @@ find $DIR/libraries -name "*.map" -type f -delete
|
||||
rm -r $DIR/src/public/app
|
||||
|
||||
sed -i -e 's/app\/desktop.js/app-dist\/desktop.js/g' $DIR/src/views/desktop.ejs
|
||||
sed -i -e 's/app\/mobile.js/app-dist\/mobile.js/g' $DIR/src/views/mobile.ejs
|
||||
sed -i -e 's/app\/mobile.js/app-dist\/mobile.js/g' $DIR/src/views/mobile.ejs
|
||||
sed -i -e 's/app\/setup.js/app-dist\/setup.js/g' $DIR/src/views/setup.ejs
|
||||
174
package-lock.json
generated
174
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trilium",
|
||||
"version": "0.41.6",
|
||||
"version": "0.42.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -1192,38 +1192,38 @@
|
||||
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
|
||||
},
|
||||
"app-builder-bin": {
|
||||
"version": "3.5.6",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.6.tgz",
|
||||
"integrity": "sha512-gY9ABoV5jh67IrPEwF81R8l9LwE3RqHUyU3rIKitwqMpKhplN5OZC6WEHOXO3XhwiLCIlr9LLI6OPhr3bmtQIg==",
|
||||
"version": "3.5.8",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.8.tgz",
|
||||
"integrity": "sha512-ni3q7QTfQNWHNWuyn5x3FZu6GnQZv+TFnfgk5++svqleKEhHGqS1mIaKsh7x5pBX6NFXU3/+ktk98wA/AW4EXw==",
|
||||
"dev": true
|
||||
},
|
||||
"app-builder-lib": {
|
||||
"version": "22.5.1",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.5.1.tgz",
|
||||
"integrity": "sha512-VtB/PD8actR1317D/0uGzuJIYbpw4pRrfMB6IyTLwGynUd3ihqiCFjejVWHjCwopgCct2kE0MvLwo8P49xHIeQ==",
|
||||
"version": "22.6.0",
|
||||
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.6.0.tgz",
|
||||
"integrity": "sha512-ky2aLYy92U+Gh6dKq/e8/bNmCotp6/GMhnX8tDZPv9detLg9WuBnWWi1ktBPlpbl1DREusy+TIh+9rgvfduQoA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"7zip-bin": "~5.0.3",
|
||||
"@develar/schema-utils": "~2.6.5",
|
||||
"async-exit-hook": "^2.0.1",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.5.1",
|
||||
"builder-util": "22.6.0",
|
||||
"builder-util-runtime": "8.7.0",
|
||||
"chromium-pickle-js": "^0.2.0",
|
||||
"debug": "^4.1.1",
|
||||
"ejs": "^3.0.2",
|
||||
"electron-publish": "22.5.1",
|
||||
"ejs": "^3.1.2",
|
||||
"electron-publish": "22.6.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"hosted-git-info": "^3.0.4",
|
||||
"is-ci": "^2.0.0",
|
||||
"isbinaryfile": "^4.0.5",
|
||||
"isbinaryfile": "^4.0.6",
|
||||
"js-yaml": "^3.13.1",
|
||||
"lazy-val": "^1.0.4",
|
||||
"minimatch": "^3.0.4",
|
||||
"normalize-package-data": "^2.5.0",
|
||||
"read-config-file": "6.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"semver": "^7.1.3",
|
||||
"semver": "^7.3.2",
|
||||
"temp-file": "^3.3.7"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -1864,23 +1864,23 @@
|
||||
}
|
||||
},
|
||||
"builder-util": {
|
||||
"version": "22.5.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.5.1.tgz",
|
||||
"integrity": "sha512-CelDTP3+fvDfZfbwy3PXif7mudPaWankJ8vrRg/NtCGvL+hXnwycnJZr46d5EQL7AgQcpJ27o9LTdfu61cxTFw==",
|
||||
"version": "22.6.0",
|
||||
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.6.0.tgz",
|
||||
"integrity": "sha512-jgdES2ExJYkuXC3DEaGAjFctKNA81C4QDy8zdoc+rqdSqheTizuDNtZg02uMFklmUES4V4fggmqds+Y7wraqng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"7zip-bin": "~5.0.3",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/fs-extra": "^8.1.0",
|
||||
"app-builder-bin": "3.5.6",
|
||||
"app-builder-bin": "3.5.8",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util-runtime": "8.7.0",
|
||||
"chalk": "^3.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"fs-extra": "^9.0.0",
|
||||
"is-ci": "^2.0.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"source-map-support": "^0.5.16",
|
||||
"source-map-support": "^0.5.19",
|
||||
"stat-mode": "^1.0.0",
|
||||
"temp-file": "^3.3.7"
|
||||
},
|
||||
@@ -1896,9 +1896,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
|
||||
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@@ -1920,6 +1920,16 @@
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"stat-mode": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
|
||||
@@ -3143,13 +3153,13 @@
|
||||
}
|
||||
},
|
||||
"dmg-builder": {
|
||||
"version": "22.5.1",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.5.1.tgz",
|
||||
"integrity": "sha512-AwIiyGwgqhA8Ty/YnEU20aSzfrWZns6suOBTqddD+rLDI4jEASKGQadfvcXRSWgaK/VQW0GrhheXrhJpzZzt3g==",
|
||||
"version": "22.6.0",
|
||||
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.6.0.tgz",
|
||||
"integrity": "sha512-rJxuGhHIpcuDGBtWZMM8aLxkbZNgYO2MO5dUerDIBXebhX1K8DA23iz/uZ8ahcRNgWEv57b8GDqJbXKEfr5T0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"app-builder-lib": "22.5.1",
|
||||
"builder-util": "22.5.1",
|
||||
"app-builder-lib": "22.6.0",
|
||||
"builder-util": "22.6.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"iconv-lite": "^0.5.1",
|
||||
"js-yaml": "^3.13.1",
|
||||
@@ -3335,9 +3345,9 @@
|
||||
}
|
||||
},
|
||||
"electron": {
|
||||
"version": "9.0.0-beta.18",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.18.tgz",
|
||||
"integrity": "sha512-mOdPB4nPc4kO2uwpvvbNZz0RDrRDIko/C8XFmOZmz7k3JaU7r0h/tLxdeypiqfLwxW/Bu1n+uwqG1X34i3fTEw==",
|
||||
"version": "9.0.0-beta.24",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.24.tgz",
|
||||
"integrity": "sha512-25L3XMqm/1CCaV5CgU5ZkhKXw9830WeipJrTW0+VC5XTKp/3xHwhxyQ5G1kQnOTJd7IGwOamvw237D6e1YKnng==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@electron/get": "^1.0.1",
|
||||
@@ -3346,18 +3356,18 @@
|
||||
}
|
||||
},
|
||||
"electron-builder": {
|
||||
"version": "22.5.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.5.1.tgz",
|
||||
"integrity": "sha512-7gnHN8Ml5zecDerN8/ljAwUKtE+hhGLuT/X2/zO0FJM2q2hlLx/6ZgzESFILKqnPQFEBRxQ8SL1OxjdIY0HIrw==",
|
||||
"version": "22.6.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.6.0.tgz",
|
||||
"integrity": "sha512-aLHlB6DTfjJ3MI4AUIFeWnwIozNgNlbOk2c2sTHxB10cAKp0dBVSPZ7xF5NK0uwDhElvRzJQubnHtJD6zKg42Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/yargs": "^15.0.4",
|
||||
"app-builder-lib": "22.5.1",
|
||||
"app-builder-lib": "22.6.0",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.5.1",
|
||||
"builder-util": "22.6.0",
|
||||
"builder-util-runtime": "8.7.0",
|
||||
"chalk": "^3.0.0",
|
||||
"dmg-builder": "22.5.1",
|
||||
"chalk": "^4.0.0",
|
||||
"dmg-builder": "22.6.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"is-ci": "^2.0.0",
|
||||
"lazy-val": "^1.0.4",
|
||||
@@ -3378,9 +3388,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
|
||||
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@@ -3724,16 +3734,16 @@
|
||||
}
|
||||
},
|
||||
"electron-publish": {
|
||||
"version": "22.5.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.5.1.tgz",
|
||||
"integrity": "sha512-g5bwLAHZT6A++yU1+Et+fncnFAdXXgkRao9rzTFAvhQ0QJBsmLiyOd0Ta2RI/EQcVoy6jyHtxFs7CWIXE5aZOA==",
|
||||
"version": "22.6.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.6.0.tgz",
|
||||
"integrity": "sha512-+v05SBf9qR7Os5au+fifloNHy5QxHQkUGudBj68YaTb43Pn37UkwRxSc49Lf13s4wW32ohM45g8BOVInPJEdnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/fs-extra": "^8.1.0",
|
||||
"bluebird-lst": "^1.0.9",
|
||||
"builder-util": "22.5.1",
|
||||
"builder-util": "22.6.0",
|
||||
"builder-util-runtime": "8.7.0",
|
||||
"chalk": "^3.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"fs-extra": "^9.0.0",
|
||||
"lazy-val": "^1.0.4",
|
||||
"mime": "^2.4.4"
|
||||
@@ -3750,9 +3760,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz",
|
||||
"integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@@ -4438,9 +4448,9 @@
|
||||
}
|
||||
},
|
||||
"file-type": {
|
||||
"version": "14.2.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-14.2.0.tgz",
|
||||
"integrity": "sha512-CAkX5G5jq8LIgFu++dpM3giMZadYdU+QVQoPLajjNboo8IzaR4cKpBCVEuz+suhd/vHqoAJeSWhEubKjRPQHJg==",
|
||||
"version": "14.3.0",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-14.3.0.tgz",
|
||||
"integrity": "sha512-s71v6jMkbfwVdj87csLeNpL5K93mv4lN+lzgzifoICtPHhnXokDwBa3jrzfg+z6FK872iYJ0vS0i74v8XmoFDA==",
|
||||
"requires": {
|
||||
"readable-web-to-node-stream": "^2.0.0",
|
||||
"strtok3": "^6.0.0",
|
||||
@@ -6207,9 +6217,9 @@
|
||||
}
|
||||
},
|
||||
"jest-worker": {
|
||||
"version": "25.4.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz",
|
||||
"integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==",
|
||||
"version": "25.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz",
|
||||
"integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"merge-stream": "^2.0.0",
|
||||
@@ -9715,7 +9725,6 @@
|
||||
"version": "2.88.0",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
|
||||
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
@@ -9742,14 +9751,12 @@
|
||||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
@@ -10110,9 +10117,9 @@
|
||||
}
|
||||
},
|
||||
"serialize-javascript": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
|
||||
"integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.0.0.tgz",
|
||||
"integrity": "sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw==",
|
||||
"dev": true
|
||||
},
|
||||
"serve-favicon": {
|
||||
@@ -10265,9 +10272,9 @@
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.16",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
|
||||
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
|
||||
"version": "0.5.19",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
|
||||
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
@@ -10341,12 +10348,13 @@
|
||||
"integrity": "sha512-1bBO+me3gXRfqwRR3K9aNDoSbTkQ87o6fSjj/BE2gSHHsK3qIDR+LoFZHgZ6kSPdFBoLTsy5/w/+8PBBaK+lvg=="
|
||||
},
|
||||
"sqlite3": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.2.0.tgz",
|
||||
"integrity": "sha512-roEOz41hxui2Q7uYnWsjMOTry6TcNUNmp8audCx18gF10P2NknwdpF+E+HKvz/F2NvPKGGBF4NGc+ZPQ+AABwg==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz",
|
||||
"integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==",
|
||||
"requires": {
|
||||
"nan": "^2.12.1",
|
||||
"node-pre-gyp": "^0.11.0"
|
||||
"node-pre-gyp": "^0.11.0",
|
||||
"request": "^2.87.0"
|
||||
}
|
||||
},
|
||||
"squeak": {
|
||||
@@ -10701,9 +10709,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"terser": {
|
||||
"version": "4.6.11",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.11.tgz",
|
||||
"integrity": "sha512-76Ynm7OXUG5xhOpblhytE7X58oeNSmC8xnNhjWVo8CksHit0U0kO4hfNbPrrYwowLWFgM2n9L176VNx2QaHmtA==",
|
||||
"version": "4.6.13",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.13.tgz",
|
||||
"integrity": "sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.20.0",
|
||||
@@ -10720,19 +10728,19 @@
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz",
|
||||
"integrity": "sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w==",
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.6.tgz",
|
||||
"integrity": "sha512-I8IDsQwZrqjdmOicNeE8L/MhwatAap3mUrtcAKJuilsemUNcX+Hier/eAzwStVqhlCxq0aG3ni9bK/0BESXkTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "^13.0.1",
|
||||
"find-cache-dir": "^3.2.0",
|
||||
"jest-worker": "^25.1.0",
|
||||
"p-limit": "^2.2.2",
|
||||
"schema-utils": "^2.6.4",
|
||||
"serialize-javascript": "^2.1.2",
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"jest-worker": "^25.4.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"schema-utils": "^2.6.6",
|
||||
"serialize-javascript": "^3.0.0",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^4.4.3",
|
||||
"terser": "^4.6.12",
|
||||
"webpack-sources": "^1.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -11458,9 +11466,9 @@
|
||||
"integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.0.0-beta.15",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.0.0-beta.15.tgz",
|
||||
"integrity": "sha512-nT+l7LteKTIzB3lmroEGL4qcCBqgHMpa3EJUvhQdfXRWjxCfWnnWdBARhp/To61omZhyNPz2Ye2J1ZEf070kWA==",
|
||||
"version": "5.0.0-beta.16",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.0.0-beta.16.tgz",
|
||||
"integrity": "sha512-O6YzI5H7XDPoXFrdC338P0GsSdhmYvz0//HL8LxVFHuRSbtHcV8mfx5U8ouWihFqwyvbfy27Bqoz2KY62kME9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@webassemblyjs/ast": "1.9.0",
|
||||
@@ -11482,7 +11490,7 @@
|
||||
"pkg-dir": "^4.2.0",
|
||||
"schema-utils": "^2.5.0",
|
||||
"tapable": "2.0.0-beta.9",
|
||||
"terser-webpack-plugin": "^2.3.1",
|
||||
"terser-webpack-plugin": "^2.3.6",
|
||||
"watchpack": "2.0.0-beta.13",
|
||||
"webpack-sources": "2.0.0-beta.8"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "trilium",
|
||||
"productName": "Trilium Notes",
|
||||
"description": "Trilium Notes",
|
||||
"version": "0.42.0-beta",
|
||||
"version": "0.42.2",
|
||||
"license": "AGPL-3.0-only",
|
||||
"main": "electron.js",
|
||||
"bin": {
|
||||
@@ -37,7 +37,7 @@
|
||||
"electron-window-state": "5.0.3",
|
||||
"express": "4.17.1",
|
||||
"express-session": "1.17.1",
|
||||
"file-type": "14.2.0",
|
||||
"file-type": "14.3.0",
|
||||
"fs-extra": "9.0.0",
|
||||
"helmet": "3.22.0",
|
||||
"html": "1.0.0",
|
||||
@@ -78,13 +78,13 @@
|
||||
"yazl": "^2.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "9.0.0-beta.22",
|
||||
"electron": "9.0.0-beta.24",
|
||||
"electron-builder": "22.6.0",
|
||||
"electron-packager": "14.2.1",
|
||||
"electron-rebuild": "1.10.1",
|
||||
"jsdoc": "3.6.4",
|
||||
"lorem-ipsum": "2.0.3",
|
||||
"webpack": "5.0.0-beta.15",
|
||||
"webpack": "5.0.0-beta.16",
|
||||
"webpack-cli": "4.0.0-beta.8"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
||||
@@ -105,7 +105,6 @@ class Attribute extends Entity {
|
||||
|
||||
// cannot be static!
|
||||
updatePojo(pojo) {
|
||||
delete pojo.isOwned;
|
||||
delete pojo.__note;
|
||||
}
|
||||
|
||||
@@ -124,4 +123,4 @@ class Attribute extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Attribute;
|
||||
module.exports = Attribute;
|
||||
|
||||
@@ -411,10 +411,6 @@ class Note extends Entity {
|
||||
}
|
||||
});
|
||||
|
||||
for (const attr of filteredAttributes) {
|
||||
attr.isOwned = attr.noteId === this.noteId;
|
||||
}
|
||||
|
||||
this.__attributeCache = filteredAttributes;
|
||||
}
|
||||
|
||||
@@ -946,4 +942,4 @@ class Note extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Note;
|
||||
module.exports = Note;
|
||||
|
||||
@@ -8,6 +8,7 @@ import contextMenu from "./services/context_menu.js";
|
||||
import DesktopMainWindowLayout from "./layouts/desktop_main_window_layout.js";
|
||||
import glob from "./services/glob.js";
|
||||
import DesktopExtraWindowLayout from "./layouts/desktop_extra_window_layout.js";
|
||||
import zoomService from './services/zoom.js';
|
||||
|
||||
glob.setupGlobs();
|
||||
|
||||
@@ -133,9 +134,11 @@ if (utils.isElectron()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const zoomLevel = zoomService.getCurrentZoom();
|
||||
|
||||
contextMenu.show({
|
||||
x: params.x,
|
||||
y: params.y,
|
||||
x: params.x / zoomLevel,
|
||||
y: params.y / zoomLevel,
|
||||
items,
|
||||
selectMenuItemHandler: ({command, spellingSuggestion}) => {
|
||||
if (command === 'replaceMisspelling') {
|
||||
@@ -144,4 +147,4 @@ if (utils.isElectron()) {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ function AttributesModel() {
|
||||
});
|
||||
};
|
||||
|
||||
async function showAttributes(attributes) {
|
||||
const ownedAttributes = attributes.filter(attr => attr.isOwned);
|
||||
async function showAttributes(noteId, attributes) {
|
||||
const ownedAttributes = attributes.filter(attr => attr.noteId === noteId);
|
||||
|
||||
for (const attr of ownedAttributes) {
|
||||
attr.labelValue = attr.type === 'label' ? attr.value : '';
|
||||
@@ -86,7 +86,7 @@ function AttributesModel() {
|
||||
|
||||
addLastEmptyRow();
|
||||
|
||||
const inheritedAttributes = attributes.filter(attr => !attr.isOwned);
|
||||
const inheritedAttributes = attributes.filter(attr => attr.noteId !== noteId);
|
||||
|
||||
self.inheritedAttributes(inheritedAttributes);
|
||||
}
|
||||
@@ -96,7 +96,7 @@ function AttributesModel() {
|
||||
|
||||
const attributes = await server.get('notes/' + noteId + '/attributes');
|
||||
|
||||
await showAttributes(attributes);
|
||||
await showAttributes(noteId, attributes);
|
||||
|
||||
// attribute might not be rendered immediatelly so could not focus
|
||||
setTimeout(() => $(".attribute-type-select:last").trigger('focus'), 1000);
|
||||
@@ -166,7 +166,7 @@ function AttributesModel() {
|
||||
|
||||
const attributes = await server.put('notes/' + noteId + '/attributes', attributesToSave);
|
||||
|
||||
await showAttributes(attributes);
|
||||
await showAttributes(noteId, attributes);
|
||||
|
||||
toastService.showMessage("Attributes have been saved.");
|
||||
};
|
||||
@@ -311,4 +311,4 @@ $dialog.on('focus', '.label-value', function (e) {
|
||||
$el: $(this),
|
||||
open: true
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,15 +37,18 @@ export async function showNoteRevisionsDialog(noteId, noteRevisionId) {
|
||||
async function loadNoteRevisions(noteId, noteRevId) {
|
||||
$list.empty();
|
||||
$content.empty();
|
||||
$titleButtons.empty();
|
||||
|
||||
note = appContext.tabManager.getActiveTabNote();
|
||||
revisionItems = await server.get(`notes/${noteId}/revisions`);
|
||||
|
||||
for (const item of revisionItems) {
|
||||
$list.append($('<a class="dropdown-item" tabindex="0">')
|
||||
.text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`)
|
||||
.attr('data-note-revision-id', item.noteRevisionId))
|
||||
.attr('title', 'This revision was last edited on ' + item.dateLastEdited);
|
||||
$list.append(
|
||||
$('<a class="dropdown-item" tabindex="0">')
|
||||
.text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`)
|
||||
.attr('data-note-revision-id', item.noteRevisionId)
|
||||
.attr('title', 'This revision was last edited on ' + item.dateLastEdited)
|
||||
);
|
||||
}
|
||||
|
||||
$listDropdown.dropdown('show');
|
||||
@@ -60,6 +63,8 @@ async function loadNoteRevisions(noteId, noteRevId) {
|
||||
$title.text("No revisions for this note yet...");
|
||||
noteRevisionId = null;
|
||||
}
|
||||
|
||||
$eraseAllRevisionsButton.toggle(revisionItems.length > 0);
|
||||
}
|
||||
|
||||
$dialog.on('shown.bs.modal', () => {
|
||||
@@ -77,6 +82,21 @@ async function setContentPane() {
|
||||
|
||||
$title.html(revisionItem.title);
|
||||
|
||||
const $restoreRevisionButton = $('<button class="btn btn-sm" type="button">Restore this revision</button>');
|
||||
|
||||
$restoreRevisionButton.on('click', async () => {
|
||||
const confirmDialog = await import('../dialogs/confirm.js');
|
||||
const text = 'Do you want to restore this revision? This will overwrite current title/content of the note with this revision.';
|
||||
|
||||
if (await confirmDialog.confirm(text)) {
|
||||
await server.put(`notes/${revisionItem.noteId}/restore-revision/${revisionItem.noteRevisionId}`);
|
||||
|
||||
$dialog.modal('hide');
|
||||
|
||||
toastService.showMessage('Note revision has been restored.');
|
||||
}
|
||||
});
|
||||
|
||||
const $eraseRevisionButton = $('<button class="btn btn-sm" type="button">Delete this revision</button>');
|
||||
|
||||
$eraseRevisionButton.on('click', async () => {
|
||||
@@ -93,6 +113,8 @@ async function setContentPane() {
|
||||
});
|
||||
|
||||
$titleButtons
|
||||
.append($restoreRevisionButton)
|
||||
.append(' ')
|
||||
.append($eraseRevisionButton)
|
||||
.append(' ');
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ import NoteRevisionsWidget from "../widgets/collapsible_widgets/note_revisions.j
|
||||
import SimilarNotesWidget from "../widgets/collapsible_widgets/similar_notes.js";
|
||||
import WhatLinksHereWidget from "../widgets/collapsible_widgets/what_links_here.js";
|
||||
import SidePaneToggles from "../widgets/side_pane_toggles.js";
|
||||
import appContext from "../services/app_context.js";
|
||||
|
||||
const RIGHT_PANE_CSS = `
|
||||
<style>
|
||||
@@ -117,6 +116,7 @@ export default class DesktopMainWindowLayout {
|
||||
.hideInZenMode())
|
||||
.child(new FlexContainer('row')
|
||||
.collapsible()
|
||||
.filling()
|
||||
.child(new SidePaneContainer('left')
|
||||
.hideInZenMode()
|
||||
.child(new GlobalButtonsWidget())
|
||||
@@ -153,4 +153,4 @@ export default class DesktopMainWindowLayout {
|
||||
.child(new SidePaneToggles().hideInZenMode())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import DialogCommandExecutor from "./dialog_command_executor.js";
|
||||
import Entrypoints from "./entrypoints.js";
|
||||
import options from "./options.js";
|
||||
import utils from "./utils.js";
|
||||
import ZoomService from "./zoom.js";
|
||||
import zoomService from "./zoom.js";
|
||||
import TabManager from "./tab_manager.js";
|
||||
import treeService from "./tree.js";
|
||||
import Component from "../widgets/component.js";
|
||||
@@ -45,10 +45,12 @@ class AppContext extends Component {
|
||||
|
||||
$("body").append($renderedWidget);
|
||||
|
||||
$renderedWidget.on('click', "[data-trigger-command]", e => {
|
||||
const commandName = $(e.target).attr('data-trigger-command');
|
||||
$renderedWidget.on('click', "[data-trigger-command]", function() {
|
||||
const commandName = $(this).attr('data-trigger-command');
|
||||
const $component = $(this).closest(".component");
|
||||
const component = $component.prop("component");
|
||||
|
||||
this.triggerCommand(commandName);
|
||||
component.triggerCommand(commandName, {$el: $(this)});
|
||||
});
|
||||
|
||||
this.tabManager = new TabManager();
|
||||
@@ -71,7 +73,7 @@ class AppContext extends Component {
|
||||
}
|
||||
|
||||
if (utils.isElectron()) {
|
||||
this.child(new ZoomService());
|
||||
this.child(zoomService);
|
||||
}
|
||||
|
||||
this.triggerEvent('initialRenderComplete');
|
||||
@@ -92,6 +94,8 @@ class AppContext extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
// this might hint at error but sometimes this is used by components which are at different places
|
||||
// in the component tree to communicate with each other
|
||||
console.debug(`Unhandled command ${name}, converting to event.`);
|
||||
|
||||
return this.triggerEvent(name, data);
|
||||
@@ -100,19 +104,6 @@ class AppContext extends Component {
|
||||
getComponentByEl(el) {
|
||||
return $(el).closest(".component").prop('component');
|
||||
}
|
||||
|
||||
async openInNewWindow(notePath) {
|
||||
if (utils.isElectron()) {
|
||||
const {ipcRenderer} = utils.dynamicRequire('electron');
|
||||
|
||||
ipcRenderer.send('create-extra-window', {notePath});
|
||||
}
|
||||
else {
|
||||
const url = window.location.protocol + '//' + window.location.host + window.location.pathname + '?extra=1#' + notePath;
|
||||
|
||||
window.open(url, '', 'width=1000,height=800');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const appContext = new AppContext(window.glob.isMainWindow);
|
||||
@@ -143,4 +134,4 @@ $(window).on('hashchange', function() {
|
||||
}
|
||||
});
|
||||
|
||||
export default appContext;
|
||||
export default appContext;
|
||||
|
||||
@@ -7,6 +7,7 @@ import Component from "../widgets/component.js";
|
||||
import toastService from "./toast.js";
|
||||
import noteCreateService from "./note_create.js";
|
||||
import ws from "./ws.js";
|
||||
import bundleService from "./bundle.js";
|
||||
|
||||
export default class Entrypoints extends Component {
|
||||
constructor() {
|
||||
@@ -182,4 +183,40 @@ export default class Entrypoints extends Component {
|
||||
}
|
||||
|
||||
createTopLevelNoteCommand() { noteCreateService.createNewTopLevelNote(); }
|
||||
|
||||
async openInWindowCommand({notePath}) {
|
||||
if (utils.isElectron()) {
|
||||
const {ipcRenderer} = utils.dynamicRequire('electron');
|
||||
|
||||
ipcRenderer.send('create-extra-window', {notePath});
|
||||
}
|
||||
else {
|
||||
const url = window.location.protocol + '//' + window.location.host + window.location.pathname + '?extra=1#' + notePath;
|
||||
|
||||
window.open(url, '', 'width=1000,height=800');
|
||||
}
|
||||
}
|
||||
|
||||
async openNewWindowCommand() {
|
||||
this.openInWindowCommand({notePath: ''});
|
||||
}
|
||||
|
||||
async runActiveNoteCommand() {
|
||||
const note = appContext.tabManager.getActiveTabNote();
|
||||
|
||||
// ctrl+enter is also used elsewhere so make sure we're running only when appropriate
|
||||
if (!note || note.type !== 'code') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (note.mime.endsWith("env=frontend")) {
|
||||
await bundleService.getAndExecuteBundle(note.noteId);
|
||||
}
|
||||
|
||||
if (note.mime.endsWith("env=backend")) {
|
||||
await server.post('script/run/' + note.noteId);
|
||||
}
|
||||
|
||||
toastService.showMessage("Note executed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ function updateDisplayedShortcuts($container) {
|
||||
}
|
||||
});
|
||||
|
||||
$container.find('button[data-command],a.icon-action[data-command],.kb-in-title').each(async (i, el) => {
|
||||
const actionName = $(el).attr('data-command');
|
||||
$container.find('[data-trigger-command]').each(async (i, el) => {
|
||||
const actionName = $(el).attr('data-trigger-command');
|
||||
const action = await getAction(actionName, true);
|
||||
|
||||
if (action) {
|
||||
|
||||
@@ -81,24 +81,29 @@ function goToLink(e) {
|
||||
}
|
||||
else if (e.which === 1) {
|
||||
const activeTabContext = appContext.tabManager.getActiveTabContext();
|
||||
activeTabContext.setNote(notePath)
|
||||
activeTabContext.setNote(notePath);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const address = $link.attr('href');
|
||||
if (e.which === 1) {
|
||||
const address = $link.attr('href');
|
||||
|
||||
if (address && address.startsWith('http')) {
|
||||
window.open(address, '_blank');
|
||||
if (address && address.startsWith('http')) {
|
||||
window.open(address, '_blank');
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function newTabContextMenu(e) {
|
||||
function linkContextMenu(e) {
|
||||
const $link = $(e.target).closest("a");
|
||||
|
||||
const notePath = getNotePathFromLink($link);
|
||||
@@ -113,8 +118,8 @@ function newTabContextMenu(e) {
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [
|
||||
{title: "Open note in new tab", command: "openNoteInNewTab", uiIcon: "arrow-up-right"},
|
||||
{title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "arrow-up-right"}
|
||||
{title: "Open note in new tab", command: "openNoteInNewTab", uiIcon: "empty"},
|
||||
{title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "window-open"}
|
||||
],
|
||||
selectMenuItemHandler: ({command}) => {
|
||||
if (command === 'openNoteInNewTab') {
|
||||
@@ -155,21 +160,23 @@ $(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,.note-detail-text a.reference-link', goToLink);
|
||||
$(document).on('mousedown', '.note-detail-text a.reference-link', goToLink);
|
||||
$(document).on('mousedown', '.note-detail-readonly-text a', goToLink);
|
||||
$(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);
|
||||
$(document).on('contextmenu', ".note-paths-widget a", newTabContextMenu);
|
||||
$(document).on('contextmenu', 'a.ck-link-actions__preview', linkContextMenu);
|
||||
$(document).on('contextmenu', '.note-detail-text a', linkContextMenu);
|
||||
$(document).on('contextmenu', '.note-detail-readonly-text a', linkContextMenu);
|
||||
$(document).on('contextmenu', "a[data-action='note']", linkContextMenu);
|
||||
$(document).on('contextmenu', ".note-detail-render a", linkContextMenu);
|
||||
$(document).on('contextmenu', ".note-paths-widget a", linkContextMenu);
|
||||
|
||||
export default {
|
||||
getNotePathFromUrl,
|
||||
createNoteLink,
|
||||
goToLink
|
||||
};
|
||||
};
|
||||
|
||||
@@ -38,12 +38,6 @@ export default class MainTreeExecutors extends Component {
|
||||
isProtected: activeNote.isProtected,
|
||||
saveSelection: false
|
||||
});
|
||||
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
||||
appContext.tabManager.getActiveTabContext().setNote(note.noteId);
|
||||
|
||||
appContext.triggerCommand('focusAndSelectTitle');
|
||||
}
|
||||
|
||||
async createNoteAfterCommand() {
|
||||
@@ -55,17 +49,11 @@ export default class MainTreeExecutors extends Component {
|
||||
return;
|
||||
}
|
||||
|
||||
const {note} = await noteCreateService.createNote(parentNoteId, {
|
||||
await noteCreateService.createNote(parentNoteId, {
|
||||
target: 'after',
|
||||
targetBranchId: node.data.branchId,
|
||||
isProtected: isProtected,
|
||||
saveSelection: true
|
||||
saveSelection: false
|
||||
});
|
||||
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
||||
appContext.tabManager.getActiveTabContext().setNote(note.noteId);
|
||||
|
||||
appContext.triggerCommand('focusAndSelectTitle');
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,12 @@ async function createNote(parentNoteId, options = {}) {
|
||||
}
|
||||
|
||||
if (options.activate) {
|
||||
await ws.waitForMaxKnownSyncId();
|
||||
|
||||
const activeTabContext = appContext.tabManager.getActiveTabContext();
|
||||
activeTabContext.setNote(note.noteId);
|
||||
await activeTabContext.setNote(note.noteId);
|
||||
|
||||
appContext.triggerCommand('focusAndSelectTitle');
|
||||
}
|
||||
|
||||
return {note, branch};
|
||||
|
||||
@@ -82,7 +82,7 @@ export default class TabManager extends Component {
|
||||
|
||||
if (filteredTabs.length === 0) {
|
||||
filteredTabs.push({
|
||||
notePath: 'root',
|
||||
notePath: this.isMainWindow ? 'root' : '',
|
||||
active: true
|
||||
});
|
||||
}
|
||||
@@ -196,7 +196,9 @@ export default class TabManager extends Component {
|
||||
async openTabWithNote(notePath, activate, tabId = null) {
|
||||
const tabContext = await this.openEmptyTab(tabId);
|
||||
|
||||
await tabContext.setNote(notePath, !activate); // if activate is false then send normal noteSwitched event
|
||||
if (notePath) {
|
||||
await tabContext.setNote(notePath, !activate); // if activate is false then send normal noteSwitched event
|
||||
}
|
||||
|
||||
if (activate) {
|
||||
this.activateTab(tabContext.tabId, false);
|
||||
@@ -330,7 +332,7 @@ export default class TabManager extends Component {
|
||||
|
||||
this.removeTab(tabId);
|
||||
|
||||
appContext.openInNewWindow(notePath);
|
||||
this.triggerCommand('openInWindow', {notePath});
|
||||
}
|
||||
|
||||
async hoistedNoteChangedEvent({hoistedNoteId}) {
|
||||
|
||||
@@ -57,7 +57,7 @@ class TreeContextMenu {
|
||||
|
||||
return [
|
||||
{ title: 'Open in a new tab <kbd>Ctrl+Click</kbd>', command: "openInTab", uiIcon: "empty", enabled: noSelectedNotes },
|
||||
{ title: 'Open in a new window', command: "openInWindow", uiIcon: "empty", enabled: noSelectedNotes },
|
||||
{ title: 'Open in a new window', command: "openInWindow", uiIcon: "window-open", enabled: noSelectedNotes },
|
||||
{ title: 'Insert note after <kbd data-command="createNoteAfter"></kbd>', command: "insertNoteAfter", uiIcon: "plus",
|
||||
items: insertNoteAfterEnabled ? this.getNoteTypeItems("insertNoteAfter") : null,
|
||||
enabled: insertNoteAfterEnabled && noSelectedNotes },
|
||||
@@ -113,9 +113,6 @@ class TreeContextMenu {
|
||||
if (command === 'openInTab') {
|
||||
appContext.tabManager.openTabWithNote(notePath);
|
||||
}
|
||||
else if (command === 'openInWindow') {
|
||||
appContext.openInNewWindow(notePath);
|
||||
}
|
||||
else if (command === "insertNoteAfter") {
|
||||
const parentNoteId = this.node.data.parentNoteId;
|
||||
const isProtected = await treeService.getParentProtectedStatus(this.node);
|
||||
@@ -134,7 +131,7 @@ class TreeContextMenu {
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.treeWidget.triggerCommand(command, {node: this.node});
|
||||
this.treeWidget.triggerCommand(command, {node: this.node, notePath: notePath});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ function subscribeToMessages(messageHandler) {
|
||||
// used to serialize sync operations
|
||||
let consumeQueuePromise = null;
|
||||
|
||||
// most sync events are sent twice - once immediatelly after finishing the transaction and once during the scheduled ping
|
||||
// but we want to process only once
|
||||
const receivedSyncIds = new Set();
|
||||
|
||||
async function handleMessage(event) {
|
||||
const message = JSON.parse(event.data);
|
||||
|
||||
@@ -52,14 +56,19 @@ async function handleMessage(event) {
|
||||
|
||||
if (syncRows.length > 0) {
|
||||
const filteredRows = syncRows.filter(row =>
|
||||
row.entityName !== 'recent_notes'
|
||||
!receivedSyncIds.has(row.id)
|
||||
&& row.entityName !== 'recent_notes'
|
||||
&& (row.entityName !== 'options' || row.entityId !== 'openTabs'));
|
||||
|
||||
if (filteredRows.length > 0) {
|
||||
console.debug(utils.now(), "Sync data: ", filteredRows);
|
||||
}
|
||||
|
||||
syncDataQueue.push(...syncRows);
|
||||
for (const row of filteredRows) {
|
||||
receivedSyncIds.add(row.id);
|
||||
}
|
||||
|
||||
syncDataQueue.push(...filteredRows);
|
||||
|
||||
// we set lastAcceptedSyncId even before sync processing and send ping so that backend can start sending more updates
|
||||
lastAcceptedSyncId = Math.max(lastAcceptedSyncId, syncRows[syncRows.length - 1].id);
|
||||
@@ -170,7 +179,7 @@ function connectWebSocket() {
|
||||
|
||||
async function sendPing() {
|
||||
if (Date.now() - lastPingTs > 30000) {
|
||||
console.log(utils.now(), "Lost websocket connection to the backend");
|
||||
console.log(utils.now(), "Lost websocket connection to the backend. If you keep having this issue repeatedly, you might want to check your reverse proxy (nginx, apache) configuration and allow/unblock WebSocket.");
|
||||
}
|
||||
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
@@ -374,4 +383,4 @@ export default {
|
||||
subscribeToMessages,
|
||||
waitForSyncId,
|
||||
waitForMaxKnownSyncId
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,31 +5,33 @@ import utils from "../services/utils.js";
|
||||
const MIN_ZOOM = 0.5;
|
||||
const MAX_ZOOM = 2.0;
|
||||
|
||||
export default class ZoomService extends Component {
|
||||
class ZoomService extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.setZoomFactor(options.getFloat('zoomFactor'));
|
||||
options.initializedPromise.then(() => {
|
||||
this.setZoomFactor(options.getFloat('zoomFactor'));
|
||||
});
|
||||
}
|
||||
|
||||
setZoomFactor(zoomFactor) {
|
||||
zoomFactor = parseFloat(zoomFactor);
|
||||
|
||||
|
||||
const webFrame = utils.dynamicRequire('electron').webFrame;
|
||||
webFrame.setZoomFactor(zoomFactor);
|
||||
}
|
||||
|
||||
|
||||
async setZoomFactorAndSave(zoomFactor) {
|
||||
if (zoomFactor >= MIN_ZOOM && zoomFactor <= MAX_ZOOM) {
|
||||
this.setZoomFactor(zoomFactor);
|
||||
|
||||
|
||||
await options.save('zoomFactor', zoomFactor);
|
||||
}
|
||||
else {
|
||||
console.log(`Zoom factor ${zoomFactor} outside of the range, ignored.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getCurrentZoom() {
|
||||
return utils.dynamicRequire('electron').webFrame.getZoomFactor();
|
||||
}
|
||||
@@ -45,4 +47,8 @@ export default class ZoomService extends Component {
|
||||
setZoomFactorAndSaveEvent({zoomFactor}) {
|
||||
this.setZoomFactorAndSave(zoomFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const zoomService = new ZoomService();
|
||||
|
||||
export default zoomService;
|
||||
|
||||
@@ -30,6 +30,11 @@ class BasicWidget extends Component {
|
||||
return this;
|
||||
}
|
||||
|
||||
filling() {
|
||||
this.css('flex-grow', '1');
|
||||
return this;
|
||||
}
|
||||
|
||||
hideInZenMode() {
|
||||
this.class('hide-in-zen-mode');
|
||||
return this;
|
||||
@@ -109,4 +114,4 @@ class BasicWidget extends Component {
|
||||
cleanup() {}
|
||||
}
|
||||
|
||||
export default BasicWidget;
|
||||
export default BasicWidget;
|
||||
|
||||
@@ -21,16 +21,16 @@ const TPL = `
|
||||
</style>
|
||||
|
||||
<tr>
|
||||
<th nowrap>Note ID:</th>
|
||||
<td nowrap colspan="3" class="note-info-note-id"></td>
|
||||
<th>Note ID:</th>
|
||||
<td colspan="3" class="note-info-note-id"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th nowrap>Created:</th>
|
||||
<td nowrap colspan="3" style="overflow: hidden; text-overflow: ellipsis;" class="note-info-date-created"></td>
|
||||
<th>Created:</th>
|
||||
<td colspan="3" class="note-info-date-created"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th nowrap>Modified:</th>
|
||||
<td nowrap colspan="3" style="overflow: hidden; text-overflow: ellipsis;" class="note-info-date-modified"></td>
|
||||
<th>Modified:</th>
|
||||
<td colspan="3" class="note-info-date-modified"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Type:</th>
|
||||
@@ -60,11 +60,11 @@ export default class NoteInfoWidget extends CollapsibleWidget {
|
||||
|
||||
this.$noteId.text(note.noteId);
|
||||
this.$dateCreated
|
||||
.text(noteComplement.dateCreated)
|
||||
.text(noteComplement.dateCreated.substr(0, 16))
|
||||
.attr("title", noteComplement.dateCreated);
|
||||
|
||||
this.$dateModified
|
||||
.text(noteComplement.dateModified)
|
||||
.text(noteComplement.dateModified.substr(0, 16))
|
||||
.attr("title", noteComplement.dateCreated);
|
||||
|
||||
this.$type.text(note.type);
|
||||
@@ -79,4 +79,4 @@ export default class NoteInfoWidget extends CollapsibleWidget {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,14 @@ const WIDGET_TPL = `
|
||||
|
||||
<a data-trigger-command="collapseTree"
|
||||
title="Collapse note tree"
|
||||
data-command="collapseTree"
|
||||
class="icon-action bx bx-layer-minus"></a>
|
||||
|
||||
<a data-trigger-command="scrollToActiveNote"
|
||||
title="Scroll to active note"
|
||||
data-command="scrollToActiveNote"
|
||||
title="Scroll to active note"
|
||||
class="icon-action bx bx-crosshair"></a>
|
||||
|
||||
<a data-trigger-command="searchNotes"
|
||||
title="Search in notes"
|
||||
data-command="searchNotes"
|
||||
class="icon-action bx bx-search"></a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import BasicWidget from "./basic_widget.js";
|
||||
import keyboardActionService from "../services/keyboard_actions.js";
|
||||
import utils from "../services/utils.js";
|
||||
import syncService from "../services/sync.js";
|
||||
|
||||
@@ -39,6 +38,12 @@ const TPL = `
|
||||
Sync (<span id="outstanding-syncs-count">0</span>)
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item" data-trigger-command="openNewWindow">
|
||||
<span class="bx bx-window-open"></span>
|
||||
Open new window
|
||||
<kbd data-command="openNewWindow"></kbd>
|
||||
</a>
|
||||
|
||||
<a class="dropdown-item open-dev-tools-button" data-trigger-command="openDevTools">
|
||||
<span class="bx bx-terminal"></span>
|
||||
Open Dev Tools
|
||||
|
||||
@@ -186,7 +186,9 @@ export default class NoteDetailWidget extends TabAwareWidget {
|
||||
const noteComplement = await this.tabContext.getNoteComplement();
|
||||
|
||||
if (note.hasLabel('readOnly') ||
|
||||
(noteComplement.content && noteComplement.content.length > 10000)) {
|
||||
(noteComplement.content
|
||||
&& noteComplement.content.length > 10000)
|
||||
&& !note.hasLabel('autoReadOnlyDisabled')) {
|
||||
type = 'read-only-text';
|
||||
}
|
||||
}
|
||||
@@ -195,7 +197,9 @@ export default class NoteDetailWidget extends TabAwareWidget {
|
||||
const noteComplement = await this.tabContext.getNoteComplement();
|
||||
|
||||
if (note.hasLabel('readOnly') ||
|
||||
(noteComplement.content && noteComplement.content.length > 30000)) {
|
||||
(noteComplement.content
|
||||
&& noteComplement.content.length > 30000)
|
||||
&& !note.hasLabel('autoReadOnlyDisabled')) {
|
||||
type = 'read-only-code';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,8 +251,8 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
this.triggerCommand('setActiveScreen', {screen:'detail'});
|
||||
}
|
||||
},
|
||||
expand: (event, data) => this.setExpandedToServer(data.node.data.branchId, true),
|
||||
collapse: (event, data) => this.setExpandedToServer(data.node.data.branchId, false),
|
||||
expand: (event, data) => this.setExpanded(data.node.data.branchId, true),
|
||||
collapse: (event, data) => this.setExpanded(data.node.data.branchId, false),
|
||||
hotkeys: utils.isMobile() ? undefined : { keydown: await this.getHotKeys() },
|
||||
dnd5: {
|
||||
autoExpandMS: 600,
|
||||
@@ -804,7 +804,9 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
|
||||
async entitiesReloadedEvent({loadResults}) {
|
||||
const activeNode = this.getActiveNode();
|
||||
const nextNode = activeNode ? (activeNode.getNextSibling() || activeNode.getPrevSibling() || activeNode.getParent()) : null;
|
||||
const activeNotePath = activeNode ? treeService.getNotePath(activeNode) : null;
|
||||
const nextNotePath = nextNode ? treeService.getNotePath(nextNode) : null;
|
||||
const activeNoteId = activeNode ? activeNode.data.noteId : null;
|
||||
|
||||
const noteIdsToUpdate = new Set();
|
||||
@@ -877,18 +879,12 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
noteIdsToUpdate.add(noteId);
|
||||
}
|
||||
|
||||
for (const noteId of noteIdsToReload) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
await node.load(true);
|
||||
|
||||
this.updateNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
await this.batchUpdate(async () => {
|
||||
for (const noteId of noteIdsToUpdate) {
|
||||
for (const noteId of noteIdsToReload) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
this.updateNode(node);
|
||||
await node.load(true);
|
||||
|
||||
noteIdsToUpdate.add(noteId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -910,6 +906,13 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
}
|
||||
});
|
||||
|
||||
// for some reason node update cannot be in the batchUpdate() block (node is not re-rendered)
|
||||
for (const noteId of noteIdsToUpdate) {
|
||||
for (const node of this.getNodesByNoteId(noteId)) {
|
||||
this.updateNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeNotePath) {
|
||||
let node = await this.expandToNote(activeNotePath);
|
||||
|
||||
@@ -925,15 +928,27 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
if (node) {
|
||||
node.setActive(true, {noEvents: true});
|
||||
}
|
||||
else {
|
||||
// this is used when original note has been deleted and we want to move the focus to the note above/below
|
||||
node = await this.expandToNote(nextNotePath);
|
||||
|
||||
if (node) {
|
||||
this.tree.setFocus();
|
||||
node.setFocus(true);
|
||||
|
||||
await appContext.tabManager.getActiveTabContext().setNote(nextNotePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async setExpandedToServer(branchId, isExpanded) {
|
||||
async setExpanded(branchId, isExpanded) {
|
||||
utils.assertArguments(branchId);
|
||||
|
||||
const expandedNum = isExpanded ? 1 : 0;
|
||||
const branch = treeCache.getBranch(branchId);
|
||||
branch.isExpanded = isExpanded;
|
||||
|
||||
await server.put('branches/' + branchId + '/expanded/' + expandedNum);
|
||||
await server.put(`branches/${branchId}/expanded/${isExpanded ? 1 : 0}`);
|
||||
}
|
||||
|
||||
async reloadTreeFromCache() {
|
||||
@@ -993,7 +1008,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (const action of actions) {
|
||||
for (const shortcut of action.effectiveShortcuts) {
|
||||
hotKeyMap[utils.normalizeShortcut(shortcut)] = node => {
|
||||
@@ -1018,83 +1033,83 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
|
||||
async deleteNotesCommand({node}) {
|
||||
const branchIds = this.getSelectedOrActiveBranchIds(node);
|
||||
|
||||
|
||||
await branchService.deleteNotes(branchIds);
|
||||
|
||||
this.clearSelectedNodes();
|
||||
}
|
||||
|
||||
|
||||
moveNoteUpCommand({node}) {
|
||||
const beforeNode = node.getPrevSibling();
|
||||
|
||||
|
||||
if (beforeNode !== null) {
|
||||
branchService.moveBeforeBranch([node.data.branchId], beforeNode.data.branchId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
moveNoteDownCommand({node}) {
|
||||
const afterNode = node.getNextSibling();
|
||||
if (afterNode !== null) {
|
||||
branchService.moveAfterBranch([node.data.branchId], afterNode.data.branchId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
moveNoteUpInHierarchyCommand({node}) {
|
||||
branchService.moveNodeUpInHierarchy(node);
|
||||
}
|
||||
|
||||
|
||||
moveNoteDownInHierarchyCommand({node}) {
|
||||
const toNode = node.getPrevSibling();
|
||||
|
||||
|
||||
if (toNode !== null) {
|
||||
branchService.moveToParentNote([node.data.branchId], toNode.data.noteId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addNoteAboveToSelectionCommand() {
|
||||
const node = this.getFocusedNode();
|
||||
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
|
||||
const prevSibling = node.getPrevSibling();
|
||||
|
||||
|
||||
if (prevSibling) {
|
||||
prevSibling.setActive(true, {noEvents: true});
|
||||
|
||||
|
||||
if (prevSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
}
|
||||
|
||||
|
||||
prevSibling.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
addNoteBelowToSelectionCommand() {
|
||||
const node = this.getFocusedNode();
|
||||
|
||||
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (node.isActive()) {
|
||||
node.setSelected(true);
|
||||
}
|
||||
|
||||
|
||||
const nextSibling = node.getNextSibling();
|
||||
|
||||
|
||||
if (nextSibling) {
|
||||
nextSibling.setActive(true, {noEvents: true});
|
||||
|
||||
|
||||
if (nextSibling.isSelected()) {
|
||||
node.setSelected(false);
|
||||
}
|
||||
|
||||
|
||||
nextSibling.setSelected(true);
|
||||
}
|
||||
}
|
||||
@@ -1178,4 +1193,4 @@ export default class NoteTreeWidget extends TabAwareWidget {
|
||||
|
||||
noteCreateService.duplicateNote(node.data.noteId, branch.parentNoteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ const TPL = `
|
||||
|
||||
.promoted-attributes td, .promoted-attributes th {
|
||||
padding: 5px;
|
||||
min-width: 50px; /* otherwise checkboxes can collapse into 0 width (if there are only checkboxes) */
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -98,7 +99,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
|
||||
const $labelCell = $("<th>").append(valueAttr.name);
|
||||
const $input = $("<input>")
|
||||
.prop("tabindex", definitionAttr.position)
|
||||
.prop("attribute-id", valueAttr.isOwned ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
|
||||
.prop("attribute-id", valueAttr.noteId === this.noteId ? valueAttr.attributeId : '') // if not owned, we'll force creation of a new attribute instead of updating the inherited one
|
||||
.prop("attribute-type", valueAttr.type)
|
||||
.prop("attribute-name", valueAttr.name)
|
||||
.prop("value", valueAttr.value)
|
||||
@@ -266,4 +267,4 @@ export default class PromotedAttributesWidget extends TabAwareWidget {
|
||||
|
||||
$attr.prop("attribute-id", result.attributeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ import TabAwareWidget from "./tab_aware_widget.js";
|
||||
const TPL = `
|
||||
<div style="display: inline-flex;">
|
||||
<button class="btn btn-sm icon-button bx bx-play-circle render-button"
|
||||
data-trigger-command="renderActiveNote"
|
||||
title="Render"></button>
|
||||
|
||||
<button class="btn btn-sm icon-button bx bx-play-circle execute-script-button"
|
||||
title="Execute (Ctrl+Enter)"></button>
|
||||
data-trigger-command="runActiveNote"
|
||||
title="Execute"></button>
|
||||
</div>`;
|
||||
|
||||
export default class RunScriptButtonsWidget extends TabAwareWidget {
|
||||
@@ -21,6 +23,12 @@ export default class RunScriptButtonsWidget extends TabAwareWidget {
|
||||
|
||||
refreshWithNote(note) {
|
||||
this.$renderButton.toggle(note.type === 'render');
|
||||
this.$executeScriptButton.toggle(note.mime.startsWith('application/javascript'));
|
||||
this.$executeScriptButton.toggle(note.type === 'code' && note.mime.startsWith('application/javascript'));
|
||||
}
|
||||
|
||||
async entitiesReloadedEvent({loadResults}) {
|
||||
if (loadResults.isNoteReloaded(this.noteId)) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,11 +29,11 @@ const TAB_TPL = `
|
||||
<div class="note-tab-wrapper">
|
||||
<div class="note-tab-title"></div>
|
||||
<div class="note-tab-drag-handle"></div>
|
||||
<div class="note-tab-close kb-in-title" title="Close tab" data-command="closeActiveTab"><span>×</span></div>
|
||||
<div class="note-tab-close" title="Close tab" data-trigger-command="closeActiveTab"><span>×</span></div>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
const NEW_TAB_BUTTON_TPL = `<div class="note-new-tab kb-in-title" data-command="openNewTab" title="Add new tab">+</div>`;
|
||||
const NEW_TAB_BUTTON_TPL = `<div class="note-new-tab" data-trigger-command="openNewTab" title="Add new tab">+</div>`;
|
||||
const FILLER_TPL = `<div class="tab-row-filler">
|
||||
<div class="tab-row-border"></div>
|
||||
</div>`;
|
||||
@@ -258,9 +258,9 @@ export default class TabRowWidget extends BasicWidget {
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items: [
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "empty"},
|
||||
{title: "Close all tabs", command: "removeAllTabs", uiIcon: "empty"},
|
||||
{title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "empty"},
|
||||
{title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "window-open"},
|
||||
{title: "Close all tabs", command: "removeAllTabs", uiIcon: "x"},
|
||||
{title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "x"},
|
||||
],
|
||||
selectMenuItemHandler: ({command}) => {
|
||||
this.triggerCommand(command, {tabId});
|
||||
@@ -394,10 +394,13 @@ export default class TabRowWidget extends BasicWidget {
|
||||
this.setupDraggabilly();
|
||||
}
|
||||
|
||||
setTabCloseEvent($tab) {
|
||||
$tab.find('.note-tab-close')
|
||||
.on('click', _ => appContext.tabManager.removeTab($tab.attr('data-tab-id')));
|
||||
closeActiveTabCommand({$el}) {
|
||||
const tabId = $el.closest(".note-tab").attr('data-tab-id');
|
||||
|
||||
appContext.tabManager.removeTab(tabId);
|
||||
}
|
||||
|
||||
setTabCloseEvent($tab) {
|
||||
$tab.on('mousedown', e => {
|
||||
if (e.which === 2) {
|
||||
appContext.tabManager.removeTab($tab.attr('data-tab-id'));
|
||||
@@ -558,8 +561,6 @@ export default class TabRowWidget extends BasicWidget {
|
||||
this.$newTab = $(NEW_TAB_BUTTON_TPL);
|
||||
|
||||
this.$tabContainer.append(this.$newTab);
|
||||
|
||||
this.$newTab.on('click', _ => this.triggerCommand('openNewTab'));
|
||||
}
|
||||
|
||||
setupFiller() {
|
||||
@@ -601,18 +602,23 @@ export default class TabRowWidget extends BasicWidget {
|
||||
}
|
||||
|
||||
updateTab($tab, note) {
|
||||
if (!note || !$tab.length) {
|
||||
if (!$tab.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateTitle($tab, note.title);
|
||||
|
||||
for (const clazz of Array.from($tab[0].classList)) { // create copy to safely iterate over while removing classes
|
||||
if (clazz !== 'note-tab') {
|
||||
$tab.removeClass(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
if (!note) {
|
||||
this.updateTitle($tab, 'New tab');
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateTitle($tab, note.title);
|
||||
|
||||
$tab.addClass(note.getCssClass());
|
||||
$tab.addClass(utils.getNoteTypeClass(note.type));
|
||||
$tab.addClass(utils.getMimeTypeClass(note.mime));
|
||||
@@ -635,4 +641,4 @@ export default class TabRowWidget extends BasicWidget {
|
||||
this.updateTab($tab, tabContext.note);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import libraryLoader from "../../services/library_loader.js";
|
||||
import bundleService from "../../services/bundle.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import server from "../../services/server.js";
|
||||
import keyboardActionService from "../../services/keyboard_actions.js";
|
||||
import TypeWidget from "./type_widget.js";
|
||||
import keyboardActionService from "../../services/keyboard_actions.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="note-detail-code note-detail-printable">
|
||||
@@ -27,11 +24,8 @@ export default class EditableCodeTypeWidget extends TypeWidget {
|
||||
doRender() {
|
||||
this.$widget = $(TPL);
|
||||
this.$editor = this.$widget.find('.note-detail-code-editor');
|
||||
this.$executeScriptButton = this.$widget.find(".execute-script-button");
|
||||
|
||||
keyboardActionService.setElementActionHandler(this.$widget, 'runActiveNote', () => this.executeCurrentNote());
|
||||
|
||||
this.$executeScriptButton.on('click', () => this.executeCurrentNote());
|
||||
keyboardActionService.setupActionsForElement('code-detail', this.$widget, this);
|
||||
|
||||
this.initialized = this.initEditor();
|
||||
|
||||
@@ -106,26 +100,6 @@ export default class EditableCodeTypeWidget extends TypeWidget {
|
||||
this.codeEditor.focus();
|
||||
}
|
||||
|
||||
async executeCurrentNote() {
|
||||
// ctrl+enter is also used elsewhere so make sure we're running only when appropriate
|
||||
if (this.note.type !== 'code') {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure note is saved so we load latest changes
|
||||
await this.spacedUpdate.updateNowIfNecessary();
|
||||
|
||||
if (this.note.mime.endsWith("env=frontend")) {
|
||||
await bundleService.getAndExecuteBundle(this.noteId);
|
||||
}
|
||||
|
||||
if (this.note.mime.endsWith("env=backend")) {
|
||||
await server.post('script/run/' + this.noteId);
|
||||
}
|
||||
|
||||
toastService.showMessage("Note executed");
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if (this.codeEditor) {
|
||||
this.spacedUpdate.allowUpdateWithoutChange(() => {
|
||||
|
||||
@@ -22,6 +22,10 @@ const TPL = `
|
||||
.note-detail-readonly-text p:first-child, .note-detail-text::before {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.note-detail-readonly-text img {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="alert alert-warning no-print">
|
||||
@@ -77,4 +81,4 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
||||
this.loadIncludedNote(noteId, $(el));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,6 @@ export default class RenderTypeWidget extends TypeWidget {
|
||||
this.$widget = $(TPL);
|
||||
this.$noteDetailRenderHelp = this.$widget.find('.note-detail-render-help');
|
||||
this.$noteDetailRenderContent = this.$widget.find('.note-detail-render-content');
|
||||
this.$renderButton = this.$widget.find('.render-button');
|
||||
|
||||
this.$renderButton.on('click', () => this.refresh());
|
||||
|
||||
return this.$widget;
|
||||
}
|
||||
@@ -46,4 +43,10 @@ export default class RenderTypeWidget extends TypeWidget {
|
||||
cleanup() {
|
||||
this.$noteDetailRenderContent.empty();
|
||||
}
|
||||
|
||||
renderActiveNoteEvent() {
|
||||
if (this.tabContext.isActive()) {
|
||||
this.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ async function updateNoteAttributes(req) {
|
||||
|| (attribute.type === 'relation' && attribute.value !== attributeEntity.value)) {
|
||||
|
||||
if (attribute.type !== 'relation' || !!attribute.value.trim()) {
|
||||
const newAttribute = attribute.createClone(attribute.type, attribute.name, attribute.value);
|
||||
const newAttribute = attributeEntity.createClone(attribute.type, attribute.name, attribute.value);
|
||||
await newAttribute.save();
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ async function updateNoteAttributes(req) {
|
||||
}
|
||||
|
||||
const note = await repository.getNote(noteId);
|
||||
note.invalidateAttributeCache();
|
||||
|
||||
return await note.getAttributes();
|
||||
}
|
||||
@@ -198,4 +199,4 @@ module.exports = {
|
||||
getEffectiveNoteAttributes,
|
||||
createRelation,
|
||||
deleteRelation
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
const noteService = require('../../services/notes');
|
||||
const protectedSessionService = require('../../services/protected_session');
|
||||
const repository = require('../../services/repository');
|
||||
const utils = require('../../services/utils');
|
||||
@@ -45,7 +44,9 @@ async function downloadNoteFile(noteId, res, contentDisposition = true) {
|
||||
if (contentDisposition) {
|
||||
// (one) reason we're not using the originFileName (available as label) is that it's not
|
||||
// available for older note revisions and thus would be inconsistent
|
||||
res.setHeader('Content-Disposition', utils.getContentDisposition(note.title || "untitled"));
|
||||
const filename = utils.formatDownloadTitle(note.title, note.type, note.mime);
|
||||
|
||||
res.setHeader('Content-Disposition', utils.getContentDisposition(filename));
|
||||
}
|
||||
|
||||
res.setHeader('Content-Type', note.mime);
|
||||
@@ -70,4 +71,4 @@ module.exports = {
|
||||
openFile,
|
||||
downloadFile,
|
||||
downloadNoteFile
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const repository = require('../../services/repository');
|
||||
const noteCacheService = require('../../services/note_cache');
|
||||
const protectedSessionService = require('../../services/protected_session');
|
||||
const noteRevisionService = require('../../services/note_revisions');
|
||||
const utils = require('../../services/utils');
|
||||
const path = require('path');
|
||||
|
||||
@@ -37,13 +38,7 @@ async function getNoteRevision(req) {
|
||||
* @return {string}
|
||||
*/
|
||||
function getRevisionFilename(noteRevision) {
|
||||
let filename = noteRevision.title || "untitled";
|
||||
|
||||
if (noteRevision.type === 'text') {
|
||||
filename += '.html';
|
||||
} else if (['relation-map', 'search'].includes(noteRevision.type)) {
|
||||
filename += '.json';
|
||||
}
|
||||
let filename = utils.formatDownloadTitle(noteRevision.title, noteRevision.type, noteRevision.mime);
|
||||
|
||||
const extension = path.extname(filename);
|
||||
const date = noteRevision.dateCreated
|
||||
@@ -109,6 +104,20 @@ async function eraseNoteRevision(req) {
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreNoteRevision(req) {
|
||||
const noteRevision = await repository.getNoteRevision(req.params.noteRevisionId);
|
||||
|
||||
if (noteRevision && !noteRevision.isErased) {
|
||||
const note = await noteRevision.getNote();
|
||||
|
||||
await noteRevisionService.createNoteRevision(note);
|
||||
|
||||
note.title = noteRevision.title;
|
||||
await note.setContent(await noteRevision.getContent());
|
||||
await note.save();
|
||||
}
|
||||
}
|
||||
|
||||
async function getEditedNotesOnDate(req) {
|
||||
const date = utils.sanitizeSql(req.params.date);
|
||||
|
||||
@@ -141,5 +150,6 @@ module.exports = {
|
||||
downloadNoteRevision,
|
||||
getEditedNotesOnDate,
|
||||
eraseAllNoteRevisions,
|
||||
eraseNoteRevision
|
||||
};
|
||||
eraseNoteRevision,
|
||||
restoreNoteRevision
|
||||
};
|
||||
|
||||
@@ -145,6 +145,7 @@ function register(app) {
|
||||
apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision);
|
||||
apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision);
|
||||
route(GET, '/api/notes/:noteId/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision);
|
||||
apiRoute(PUT, '/api/notes/:noteId/restore-revision/:noteRevisionId', noteRevisionsApiRoute.restoreNoteRevision);
|
||||
apiRoute(POST, '/api/notes/relation-map', notesApiRoute.getRelationMap);
|
||||
apiRoute(PUT, '/api/notes/:noteId/change-title', notesApiRoute.changeTitle);
|
||||
apiRoute(POST, '/api/notes/:noteId/duplicate/:parentNoteId', notesApiRoute.duplicateNote);
|
||||
|
||||
@@ -6,9 +6,8 @@ const utils = require('../services/utils');
|
||||
|
||||
async function setupPage(req, res) {
|
||||
if (await sqlInit.isDbInitialized()) {
|
||||
const windowService = require('../services/window');
|
||||
|
||||
if (utils.isElectron()) {
|
||||
const windowService = require('../services/window');
|
||||
await windowService.createMainWindow();
|
||||
windowService.closeSetupWindow();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ const BUILTIN_ATTRIBUTES = [
|
||||
{ type: 'label', name: 'appTheme' },
|
||||
{ type: 'label', name: 'hidePromotedAttributes' },
|
||||
{ type: 'label', name: 'readOnly' },
|
||||
{ type: 'label', name: 'autoReadOnlyDisabled' },
|
||||
{ type: 'label', name: 'cssClass' },
|
||||
{ type: 'label', name: 'iconClass' },
|
||||
{ type: 'label', name: 'keyboardShortcut' },
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = { buildDate:"2020-05-04T21:59:14+02:00", buildRevision: "cafcb67a8a3a1943acac829590b34ff729b57e09" };
|
||||
module.exports = { buildDate:"2020-05-12T16:46:45+02:00", buildRevision: "4f50864ec8346a12d7845cb4c91a3de3b1043d34" };
|
||||
|
||||
@@ -193,7 +193,7 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
||||
|
||||
|
||||
{
|
||||
separator: "Tabs"
|
||||
separator: "Tabs & Windows"
|
||||
},
|
||||
{
|
||||
actionName: "openNewTab",
|
||||
@@ -219,6 +219,12 @@ const DEFAULT_KEYBOARD_ACTIONS = [
|
||||
description: "Activates tab on the left",
|
||||
scope: "window"
|
||||
},
|
||||
{
|
||||
actionName: "openNewWindow",
|
||||
defaultShortcuts: [],
|
||||
description: "Open new empty window",
|
||||
scope: "window"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ const Attribute = require('../entities/attribute');
|
||||
const hoistedNoteService = require('../services/hoisted_note');
|
||||
const protectedSessionService = require('../services/protected_session');
|
||||
const log = require('../services/log');
|
||||
const utils = require('../services/utils');
|
||||
const noteRevisionService = require('../services/note_revisions');
|
||||
const attributeService = require('../services/attributes');
|
||||
const request = require('./request');
|
||||
@@ -276,9 +277,9 @@ async function downloadImage(noteId, imageUrl) {
|
||||
const downloadImagePromises = {};
|
||||
|
||||
function replaceUrl(content, url, imageNote) {
|
||||
const quoted = url.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
||||
const quotedUrl = utils.quoteRegex(url);
|
||||
|
||||
return content.replace(new RegExp(`\\s+src=[\"']${quoted}[\"']`, "g"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`);
|
||||
return content.replace(new RegExp(`\\s+src=[\"']${quotedUrl}[\"']`, "g"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`);
|
||||
}
|
||||
|
||||
async function downloadImages(noteId, content) {
|
||||
@@ -293,15 +294,11 @@ async function downloadImages(noteId, content) {
|
||||
if (!url.includes('api/images/')
|
||||
// this is and exception for the web clipper's "imageId"
|
||||
&& (url.length !== 20 || url.toLowerCase().startsWith('http'))) {
|
||||
if (url in downloadImagePromises) {
|
||||
// download is already in progress
|
||||
continue;
|
||||
}
|
||||
|
||||
if (url in imageUrlToNoteIdMapping) {
|
||||
const imageNote = await repository.getNote(imageUrlToNoteIdMapping[url]);
|
||||
|
||||
if (imageNote || imageNote.isDeleted) {
|
||||
if (!imageNote || imageNote.isDeleted) {
|
||||
delete imageUrlToNoteIdMapping[url];
|
||||
}
|
||||
else {
|
||||
@@ -322,6 +319,11 @@ async function downloadImages(noteId, content) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (url in downloadImagePromises) {
|
||||
// download is already in progress
|
||||
continue;
|
||||
}
|
||||
|
||||
// this is done asynchronously, it would be too slow to wait for the download
|
||||
// given that save can be triggered very often
|
||||
downloadImagePromises[url] = downloadImage(noteId, url);
|
||||
@@ -338,28 +340,30 @@ async function downloadImages(noteId, content) {
|
||||
// are downloaded and the IMG references are not updated. For this occassion we have this code
|
||||
// which upon the download of all the images will update the note if the links have not been fixed before
|
||||
|
||||
const imageNotes = await repository.getNotes(Object.values(imageUrlToNoteIdMapping));
|
||||
await sql.transactional(async () => {
|
||||
const imageNotes = await repository.getNotes(Object.values(imageUrlToNoteIdMapping));
|
||||
|
||||
const origNote = await repository.getNote(noteId);
|
||||
const origContent = await origNote.getContent();
|
||||
let updatedContent = origContent;
|
||||
const origNote = await repository.getNote(noteId);
|
||||
const origContent = await origNote.getContent();
|
||||
let updatedContent = origContent;
|
||||
|
||||
for (const url in imageUrlToNoteIdMapping) {
|
||||
const imageNote = imageNotes.find(note => note.noteId === imageUrlToNoteIdMapping[url]);
|
||||
for (const url in imageUrlToNoteIdMapping) {
|
||||
const imageNote = imageNotes.find(note => note.noteId === imageUrlToNoteIdMapping[url]);
|
||||
|
||||
if (imageNote && !imageNote.isDeleted) {
|
||||
updatedContent = replaceUrl(updatedContent, url, imageNote);
|
||||
if (imageNote && !imageNote.isDeleted) {
|
||||
updatedContent = replaceUrl(updatedContent, url, imageNote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update only if the links have not been already fixed.
|
||||
if (updatedContent !== origContent) {
|
||||
await origNote.setContent(updatedContent);
|
||||
// update only if the links have not been already fixed.
|
||||
if (updatedContent !== origContent) {
|
||||
await origNote.setContent(updatedContent);
|
||||
|
||||
await scanForLinks(origNote);
|
||||
await scanForLinks(origNote);
|
||||
|
||||
console.log(`Fixed the image links for note ${noteId} to the offline saved.`);
|
||||
}
|
||||
console.log(`Fixed the image links for note ${noteId} to the offline saved.`);
|
||||
}
|
||||
});
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const dayjs = require("dayjs");
|
||||
|
||||
const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\p{L}\p{Number}_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*([^\s=*]+|"[^"]+"))?/igu;
|
||||
const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\p{L}\p{Number}_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*([^\s=*"]+|"[^"]+"))?/igu;
|
||||
const smartValueRegex = /^(NOW|TODAY|WEEK|MONTH|YEAR) *([+\-] *\d+)?$/i;
|
||||
|
||||
function calculateSmartValue(v) {
|
||||
|
||||
@@ -221,6 +221,7 @@ async function transactional(func) {
|
||||
|
||||
await commit();
|
||||
|
||||
// note that sync rows sent from this action will be sent again by scheduled periodic ping
|
||||
require('./ws.js').sendPingToAllClients();
|
||||
|
||||
transactionActive = false;
|
||||
@@ -267,4 +268,4 @@ module.exports = {
|
||||
executeScript,
|
||||
transactional,
|
||||
upsert
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ const randtoken = require('rand-token').generator({source: 'crypto'});
|
||||
const unescape = require('unescape');
|
||||
const escape = require('escape-html');
|
||||
const sanitize = require("sanitize-filename");
|
||||
const mimeTypes = require('mime-types');
|
||||
|
||||
function newEntityId() {
|
||||
return randomString(12);
|
||||
@@ -166,10 +167,46 @@ function isStringNote(type, mime) {
|
||||
|| STRING_MIME_TYPES.includes(mime);
|
||||
}
|
||||
|
||||
function replaceAll(string, replaceWhat, replaceWith) {
|
||||
const escapedWhat = replaceWhat.replace(/([\/,!\\^${}\[\]().*+?|<>\-&])/g, "\\$&");
|
||||
function quoteRegex(url) {
|
||||
return url.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
return string.replace(new RegExp(escapedWhat, "g"), replaceWith);
|
||||
function replaceAll(string, replaceWhat, replaceWith) {
|
||||
const quotedReplaceWhat = quoteRegex(replaceWhat);
|
||||
|
||||
return string.replace(new RegExp(quotedReplaceWhat, "g"), replaceWith);
|
||||
}
|
||||
|
||||
function formatDownloadTitle(filename, type, mime) {
|
||||
if (!filename) {
|
||||
filename = "untitled";
|
||||
}
|
||||
|
||||
if (type === 'text') {
|
||||
return filename + '.html';
|
||||
} else if (['relation-map', 'search'].includes(type)) {
|
||||
return filename + '.json';
|
||||
} else {
|
||||
if (!mime) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
mime = mime.toLowerCase();
|
||||
const filenameLc = filename.toLowerCase();
|
||||
const extensions = mimeTypes.extensions[mime];
|
||||
|
||||
if (!extensions || extensions.length === 0) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
for (const ext of extensions) {
|
||||
if (filenameLc.endsWith('.' + ext)) {
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
|
||||
return filename + '.' + extensions[0];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
@@ -198,5 +235,7 @@ module.exports = {
|
||||
sanitizeFilenameForHeader,
|
||||
getContentDisposition,
|
||||
isStringNote,
|
||||
replaceAll
|
||||
};
|
||||
quoteRegex,
|
||||
replaceAll,
|
||||
formatDownloadTitle
|
||||
};
|
||||
|
||||
@@ -165,6 +165,5 @@ module.exports = {
|
||||
createMainWindow,
|
||||
createSetupWindow,
|
||||
closeSetupWindow,
|
||||
createExtraWindow,
|
||||
registerGlobalShortcuts
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<title>Trilium Notes</title>
|
||||
</head>
|
||||
<body class="desktop theme-<%= theme %>" style="display: none; --main-font-size: <%= mainFontSize %>%; --tree-font-size: <%= treeFontSize %>%; --detail-font-size: <%= detailFontSize %>%;">
|
||||
<body class="desktop theme-<%= theme %>" style="--main-font-size: <%= mainFontSize %>%; --tree-font-size: <%= treeFontSize %>%; --detail-font-size: <%= detailFontSize %>%;">
|
||||
<noscript>Trilium requires JavaScript to be enabled.</noscript>
|
||||
|
||||
<div id="toast-container" class="d-flex flex-column justify-content-center align-items-center"></div>
|
||||
@@ -83,9 +83,5 @@
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="libraries/boxicons/css/boxicons.min.css">
|
||||
|
||||
<script>
|
||||
$("body").show();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -210,7 +210,7 @@
|
||||
|
||||
<script src="libraries/knockout.min.js"></script>
|
||||
|
||||
<script src="app-dist/setup.js" crossorigin type="module"></script>
|
||||
<script src="app/setup.js" crossorigin type="module"></script>
|
||||
<link href="stylesheets/themes.css" rel="stylesheet">
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user