mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 37da0adb8a | ||
|  | 4f50864ec8 | ||
|  | 30b9ef8604 | ||
|  | b063b4c528 | ||
|  | e08b0141a4 | ||
|  | 9d8b8e26a1 | ||
|  | cb70109ee7 | ||
|  | e541abbd60 | ||
|  | 940a70adc5 | ||
|  | 88e8eb7e9c | ||
|  | b365c186a1 | ||
|  | 64c9734f05 | ||
|  | 48c843c087 | ||
|  | 0e4eec10b9 | ||
|  | a3661cb763 | ||
|  | 115879ec4a | 
| @@ -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 | # Create app directory | ||||||
| WORKDIR /usr/src/app | WORKDIR /usr/src/app | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| #!/usr/bin/env bash | #!/usr/bin/env bash | ||||||
|  |  | ||||||
| PKG_DIR=dist/trilium-linux-x64-server | PKG_DIR=dist/trilium-linux-x64-server | ||||||
| NODE_VERSION=12.16.2 | NODE_VERSION=12.16.3 | ||||||
|  |  | ||||||
| if [ "$1" != "DONTCOPY" ] | if [ "$1" != "DONTCOPY" ] | ||||||
| then | then | ||||||
|   | |||||||
| @@ -35,3 +35,4 @@ 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\/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 | ||||||
							
								
								
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "version": "0.42.0-beta", |   "version": "0.42.1", | ||||||
|   "lockfileVersion": 1, |   "lockfileVersion": 1, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
| @@ -3345,9 +3345,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "electron": { |     "electron": { | ||||||
|       "version": "9.0.0-beta.22", |       "version": "9.0.0-beta.24", | ||||||
|       "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.22.tgz", |       "resolved": "https://registry.npmjs.org/electron/-/electron-9.0.0-beta.24.tgz", | ||||||
|       "integrity": "sha512-dfqAf+CXXTKcNDj7DU7mYsmx+oZQcXOvJnZ8ZsgAHjrE9Tv8zsYUgCP3JlO4Z8CIazgleKXYmgh6H2stdK7fEA==", |       "integrity": "sha512-25L3XMqm/1CCaV5CgU5ZkhKXw9830WeipJrTW0+VC5XTKp/3xHwhxyQ5G1kQnOTJd7IGwOamvw237D6e1YKnng==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": { |       "requires": { | ||||||
|         "@electron/get": "^1.0.1", |         "@electron/get": "^1.0.1", | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
|   "name": "trilium", |   "name": "trilium", | ||||||
|   "productName": "Trilium Notes", |   "productName": "Trilium Notes", | ||||||
|   "description": "Trilium Notes", |   "description": "Trilium Notes", | ||||||
|   "version": "0.42.1", |   "version": "0.42.2", | ||||||
|   "license": "AGPL-3.0-only", |   "license": "AGPL-3.0-only", | ||||||
|   "main": "electron.js", |   "main": "electron.js", | ||||||
|   "bin": { |   "bin": { | ||||||
| @@ -78,7 +78,7 @@ | |||||||
|     "yazl": "^2.5.1" |     "yazl": "^2.5.1" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "electron": "9.0.0-beta.22", |     "electron": "9.0.0-beta.24", | ||||||
|     "electron-builder": "22.6.0", |     "electron-builder": "22.6.0", | ||||||
|     "electron-packager": "14.2.1", |     "electron-packager": "14.2.1", | ||||||
|     "electron-rebuild": "1.10.1", |     "electron-rebuild": "1.10.1", | ||||||
|   | |||||||
| @@ -105,7 +105,6 @@ class Attribute extends Entity { | |||||||
|  |  | ||||||
|     // cannot be static! |     // cannot be static! | ||||||
|     updatePojo(pojo) { |     updatePojo(pojo) { | ||||||
|         delete pojo.isOwned; |  | ||||||
|         delete pojo.__note; |         delete pojo.__note; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -411,10 +411,6 @@ class Note extends Entity { | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         for (const attr of filteredAttributes) { |  | ||||||
|             attr.isOwned = attr.noteId === this.noteId; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.__attributeCache = filteredAttributes; |         this.__attributeCache = filteredAttributes; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ import contextMenu from "./services/context_menu.js"; | |||||||
| import DesktopMainWindowLayout from "./layouts/desktop_main_window_layout.js"; | import DesktopMainWindowLayout from "./layouts/desktop_main_window_layout.js"; | ||||||
| import glob from "./services/glob.js"; | import glob from "./services/glob.js"; | ||||||
| import DesktopExtraWindowLayout from "./layouts/desktop_extra_window_layout.js"; | import DesktopExtraWindowLayout from "./layouts/desktop_extra_window_layout.js"; | ||||||
|  | import zoomService from './services/zoom.js'; | ||||||
|  |  | ||||||
| glob.setupGlobs(); | glob.setupGlobs(); | ||||||
|  |  | ||||||
| @@ -133,9 +134,11 @@ if (utils.isElectron()) { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         const zoomLevel = zoomService.getCurrentZoom(); | ||||||
|  |  | ||||||
|         contextMenu.show({ |         contextMenu.show({ | ||||||
|             x: params.x, |             x: params.x / zoomLevel, | ||||||
|             y: params.y, |             y: params.y / zoomLevel, | ||||||
|             items, |             items, | ||||||
|             selectMenuItemHandler: ({command, spellingSuggestion}) => { |             selectMenuItemHandler: ({command, spellingSuggestion}) => { | ||||||
|                 if (command === 'replaceMisspelling') { |                 if (command === 'replaceMisspelling') { | ||||||
|   | |||||||
| @@ -59,8 +59,8 @@ function AttributesModel() { | |||||||
|         }); |         }); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     async function showAttributes(attributes) { |     async function showAttributes(noteId, attributes) { | ||||||
|         const ownedAttributes = attributes.filter(attr => attr.isOwned); |         const ownedAttributes = attributes.filter(attr => attr.noteId === noteId); | ||||||
|  |  | ||||||
|         for (const attr of ownedAttributes) { |         for (const attr of ownedAttributes) { | ||||||
|             attr.labelValue = attr.type === 'label' ? attr.value : ''; |             attr.labelValue = attr.type === 'label' ? attr.value : ''; | ||||||
| @@ -86,7 +86,7 @@ function AttributesModel() { | |||||||
|  |  | ||||||
|         addLastEmptyRow(); |         addLastEmptyRow(); | ||||||
|  |  | ||||||
|         const inheritedAttributes = attributes.filter(attr => !attr.isOwned); |         const inheritedAttributes = attributes.filter(attr => attr.noteId !== noteId); | ||||||
|  |  | ||||||
|         self.inheritedAttributes(inheritedAttributes); |         self.inheritedAttributes(inheritedAttributes); | ||||||
|     } |     } | ||||||
| @@ -96,7 +96,7 @@ function AttributesModel() { | |||||||
|  |  | ||||||
|         const attributes = await server.get('notes/' + noteId + '/attributes'); |         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 |         // attribute might not be rendered immediatelly so could not focus | ||||||
|         setTimeout(() => $(".attribute-type-select:last").trigger('focus'), 1000); |         setTimeout(() => $(".attribute-type-select:last").trigger('focus'), 1000); | ||||||
| @@ -166,7 +166,7 @@ function AttributesModel() { | |||||||
|  |  | ||||||
|         const attributes = await server.put('notes/' + noteId + '/attributes', attributesToSave); |         const attributes = await server.put('notes/' + noteId + '/attributes', attributesToSave); | ||||||
|  |  | ||||||
|         await showAttributes(attributes); |         await showAttributes(noteId, attributes); | ||||||
|  |  | ||||||
|         toastService.showMessage("Attributes have been saved."); |         toastService.showMessage("Attributes have been saved."); | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -37,15 +37,18 @@ export async function showNoteRevisionsDialog(noteId, noteRevisionId) { | |||||||
| async function loadNoteRevisions(noteId, noteRevId) { | async function loadNoteRevisions(noteId, noteRevId) { | ||||||
|     $list.empty(); |     $list.empty(); | ||||||
|     $content.empty(); |     $content.empty(); | ||||||
|  |     $titleButtons.empty(); | ||||||
|  |  | ||||||
|     note = appContext.tabManager.getActiveTabNote(); |     note = appContext.tabManager.getActiveTabNote(); | ||||||
|     revisionItems = await server.get(`notes/${noteId}/revisions`); |     revisionItems = await server.get(`notes/${noteId}/revisions`); | ||||||
|  |  | ||||||
|     for (const item of revisionItems) { |     for (const item of revisionItems) { | ||||||
|         $list.append($('<a class="dropdown-item" tabindex="0">') |         $list.append( | ||||||
|  |             $('<a class="dropdown-item" tabindex="0">') | ||||||
|                 .text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`) |                 .text(item.dateLastEdited.substr(0, 16) + ` (${item.contentLength} bytes)`) | ||||||
|             .attr('data-note-revision-id', item.noteRevisionId)) |                 .attr('data-note-revision-id', item.noteRevisionId) | ||||||
|             .attr('title', 'This revision was last edited on ' + item.dateLastEdited); |                 .attr('title', 'This revision was last edited on ' + item.dateLastEdited) | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $listDropdown.dropdown('show'); |     $listDropdown.dropdown('show'); | ||||||
| @@ -60,6 +63,8 @@ async function loadNoteRevisions(noteId, noteRevId) { | |||||||
|         $title.text("No revisions for this note yet..."); |         $title.text("No revisions for this note yet..."); | ||||||
|         noteRevisionId = null; |         noteRevisionId = null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     $eraseAllRevisionsButton.toggle(revisionItems.length > 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| $dialog.on('shown.bs.modal', () => { | $dialog.on('shown.bs.modal', () => { | ||||||
| @@ -77,6 +82,21 @@ async function setContentPane() { | |||||||
|  |  | ||||||
|     $title.html(revisionItem.title); |     $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>'); |     const $eraseRevisionButton = $('<button class="btn btn-sm" type="button">Delete this revision</button>'); | ||||||
|  |  | ||||||
|     $eraseRevisionButton.on('click', async () => { |     $eraseRevisionButton.on('click', async () => { | ||||||
| @@ -93,6 +113,8 @@ async function setContentPane() { | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     $titleButtons |     $titleButtons | ||||||
|  |         .append($restoreRevisionButton) | ||||||
|  |         .append('   ') | ||||||
|         .append($eraseRevisionButton) |         .append($eraseRevisionButton) | ||||||
|         .append('   '); |         .append('   '); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -24,7 +24,6 @@ import NoteRevisionsWidget from "../widgets/collapsible_widgets/note_revisions.j | |||||||
| import SimilarNotesWidget from "../widgets/collapsible_widgets/similar_notes.js"; | import SimilarNotesWidget from "../widgets/collapsible_widgets/similar_notes.js"; | ||||||
| import WhatLinksHereWidget from "../widgets/collapsible_widgets/what_links_here.js"; | import WhatLinksHereWidget from "../widgets/collapsible_widgets/what_links_here.js"; | ||||||
| import SidePaneToggles from "../widgets/side_pane_toggles.js"; | import SidePaneToggles from "../widgets/side_pane_toggles.js"; | ||||||
| import appContext from "../services/app_context.js"; |  | ||||||
|  |  | ||||||
| const RIGHT_PANE_CSS = ` | const RIGHT_PANE_CSS = ` | ||||||
| <style> | <style> | ||||||
| @@ -117,6 +116,7 @@ export default class DesktopMainWindowLayout { | |||||||
|                 .hideInZenMode()) |                 .hideInZenMode()) | ||||||
|             .child(new FlexContainer('row') |             .child(new FlexContainer('row') | ||||||
|                 .collapsible() |                 .collapsible() | ||||||
|  |                 .filling() | ||||||
|                 .child(new SidePaneContainer('left') |                 .child(new SidePaneContainer('left') | ||||||
|                     .hideInZenMode() |                     .hideInZenMode() | ||||||
|                     .child(new GlobalButtonsWidget()) |                     .child(new GlobalButtonsWidget()) | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import DialogCommandExecutor from "./dialog_command_executor.js"; | |||||||
| import Entrypoints from "./entrypoints.js"; | import Entrypoints from "./entrypoints.js"; | ||||||
| import options from "./options.js"; | import options from "./options.js"; | ||||||
| import utils from "./utils.js"; | import utils from "./utils.js"; | ||||||
| import ZoomService from "./zoom.js"; | import zoomService from "./zoom.js"; | ||||||
| import TabManager from "./tab_manager.js"; | import TabManager from "./tab_manager.js"; | ||||||
| import treeService from "./tree.js"; | import treeService from "./tree.js"; | ||||||
| import Component from "../widgets/component.js"; | import Component from "../widgets/component.js"; | ||||||
| @@ -73,7 +73,7 @@ class AppContext extends Component { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (utils.isElectron()) { |         if (utils.isElectron()) { | ||||||
|             this.child(new ZoomService()); |             this.child(zoomService); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.triggerEvent('initialRenderComplete'); |         this.triggerEvent('initialRenderComplete'); | ||||||
|   | |||||||
| @@ -81,24 +81,29 @@ function goToLink(e) { | |||||||
|         } |         } | ||||||
|         else if (e.which === 1) { |         else if (e.which === 1) { | ||||||
|             const activeTabContext = appContext.tabManager.getActiveTabContext(); |             const activeTabContext = appContext.tabManager.getActiveTabContext(); | ||||||
|             activeTabContext.setNote(notePath) |             activeTabContext.setNote(notePath); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  |         if (e.which === 1) { | ||||||
|             const address = $link.attr('href'); |             const address = $link.attr('href'); | ||||||
|  |  | ||||||
|             if (address && address.startsWith('http')) { |             if (address && address.startsWith('http')) { | ||||||
|                 window.open(address, '_blank'); |                 window.open(address, '_blank'); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| function newTabContextMenu(e) { | function linkContextMenu(e) { | ||||||
|     const $link = $(e.target).closest("a"); |     const $link = $(e.target).closest("a"); | ||||||
|  |  | ||||||
|     const notePath = getNotePathFromLink($link); |     const notePath = getNotePathFromLink($link); | ||||||
| @@ -113,7 +118,7 @@ function newTabContextMenu(e) { | |||||||
|         x: e.pageX, |         x: e.pageX, | ||||||
|         y: e.pageY, |         y: e.pageY, | ||||||
|         items: [ |         items: [ | ||||||
|             {title: "Open note in new tab", command: "openNoteInNewTab", 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"} |             {title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "window-open"} | ||||||
|         ], |         ], | ||||||
|         selectMenuItemHandler: ({command}) => { |         selectMenuItemHandler: ({command}) => { | ||||||
| @@ -155,18 +160,20 @@ $(document).on('mousedown', '.note-detail-text a', function (e) { | |||||||
|  |  | ||||||
| $(document).on('mousedown', '.note-detail-book a', goToLink); | $(document).on('mousedown', '.note-detail-book a', goToLink); | ||||||
| $(document).on('mousedown', '.note-detail-render a', goToLink); | $(document).on('mousedown', '.note-detail-render a', goToLink); | ||||||
| $(document).on('mousedown', '.note-detail-text.ck-read-only a,.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('mousedown', 'a.ck-link-actions__preview', goToLink); | ||||||
| $(document).on('click', 'a.ck-link-actions__preview', e => { | $(document).on('click', 'a.ck-link-actions__preview', e => { | ||||||
|     e.preventDefault(); |     e.preventDefault(); | ||||||
|     e.stopPropagation(); |     e.stopPropagation(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| $(document).on('contextmenu', 'a.ck-link-actions__preview', newTabContextMenu); | $(document).on('contextmenu', 'a.ck-link-actions__preview', linkContextMenu); | ||||||
| $(document).on('contextmenu', '.note-detail-text a', newTabContextMenu); | $(document).on('contextmenu', '.note-detail-text a', linkContextMenu); | ||||||
| $(document).on('contextmenu', "a[data-action='note']", newTabContextMenu); | $(document).on('contextmenu', '.note-detail-readonly-text a', linkContextMenu); | ||||||
| $(document).on('contextmenu', ".note-detail-render a", newTabContextMenu); | $(document).on('contextmenu', "a[data-action='note']", linkContextMenu); | ||||||
| $(document).on('contextmenu', ".note-paths-widget a", newTabContextMenu); | $(document).on('contextmenu', ".note-detail-render a", linkContextMenu); | ||||||
|  | $(document).on('contextmenu', ".note-paths-widget a", linkContextMenu); | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|     getNotePathFromUrl, |     getNotePathFromUrl, | ||||||
|   | |||||||
| @@ -37,6 +37,10 @@ function subscribeToMessages(messageHandler) { | |||||||
| // used to serialize sync operations | // used to serialize sync operations | ||||||
| let consumeQueuePromise = null; | 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) { | async function handleMessage(event) { | ||||||
|     const message = JSON.parse(event.data); |     const message = JSON.parse(event.data); | ||||||
|  |  | ||||||
| @@ -52,14 +56,19 @@ async function handleMessage(event) { | |||||||
|  |  | ||||||
|         if (syncRows.length > 0) { |         if (syncRows.length > 0) { | ||||||
|             const filteredRows = syncRows.filter(row => |             const filteredRows = syncRows.filter(row => | ||||||
|                 row.entityName !== 'recent_notes' |                 !receivedSyncIds.has(row.id) | ||||||
|  |                 && row.entityName !== 'recent_notes' | ||||||
|                 && (row.entityName !== 'options' || row.entityId !== 'openTabs')); |                 && (row.entityName !== 'options' || row.entityId !== 'openTabs')); | ||||||
|  |  | ||||||
|             if (filteredRows.length > 0) { |             if (filteredRows.length > 0) { | ||||||
|                 console.debug(utils.now(), "Sync data: ", filteredRows); |                 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 |             // 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); |             lastAcceptedSyncId = Math.max(lastAcceptedSyncId, syncRows[syncRows.length - 1].id); | ||||||
| @@ -170,7 +179,7 @@ function connectWebSocket() { | |||||||
|  |  | ||||||
| async function sendPing() { | async function sendPing() { | ||||||
|     if (Date.now() - lastPingTs > 30000) { |     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) { |     if (ws.readyState === ws.OPEN) { | ||||||
|   | |||||||
| @@ -5,11 +5,13 @@ import utils from "../services/utils.js"; | |||||||
| const MIN_ZOOM = 0.5; | const MIN_ZOOM = 0.5; | ||||||
| const MAX_ZOOM = 2.0; | const MAX_ZOOM = 2.0; | ||||||
|  |  | ||||||
| export default class ZoomService extends Component { | class ZoomService extends Component { | ||||||
|     constructor() { |     constructor() { | ||||||
|         super(); |         super(); | ||||||
|  |  | ||||||
|  |         options.initializedPromise.then(() => { | ||||||
|             this.setZoomFactor(options.getFloat('zoomFactor')); |             this.setZoomFactor(options.getFloat('zoomFactor')); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     setZoomFactor(zoomFactor) { |     setZoomFactor(zoomFactor) { | ||||||
| @@ -46,3 +48,7 @@ export default class ZoomService extends Component { | |||||||
|         this.setZoomFactorAndSave(zoomFactor); |         this.setZoomFactorAndSave(zoomFactor); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const zoomService = new ZoomService(); | ||||||
|  |  | ||||||
|  | export default zoomService; | ||||||
|   | |||||||
| @@ -30,6 +30,11 @@ class BasicWidget extends Component { | |||||||
|         return this; |         return this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     filling() { | ||||||
|  |         this.css('flex-grow', '1'); | ||||||
|  |         return this; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     hideInZenMode() { |     hideInZenMode() { | ||||||
|         this.class('hide-in-zen-mode'); |         this.class('hide-in-zen-mode'); | ||||||
|         return this; |         return this; | ||||||
|   | |||||||
| @@ -22,15 +22,15 @@ const TPL = ` | |||||||
|  |  | ||||||
|     <tr> |     <tr> | ||||||
|         <th>Note ID:</th> |         <th>Note ID:</th> | ||||||
|         <td nowrap colspan="3" class="note-info-note-id"></td> |         <td colspan="3" class="note-info-note-id"></td> | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|         <th>Created:</th> |         <th>Created:</th> | ||||||
|         <td nowrap colspan="3" style="overflow: hidden; text-overflow: ellipsis;" class="note-info-date-created"></td> |         <td colspan="3" class="note-info-date-created"></td> | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|         <th>Modified:</th> |         <th>Modified:</th> | ||||||
|         <td nowrap colspan="3" style="overflow: hidden; text-overflow: ellipsis;" class="note-info-date-modified"></td> |         <td colspan="3" class="note-info-date-modified"></td> | ||||||
|     </tr> |     </tr> | ||||||
|     <tr> |     <tr> | ||||||
|         <th>Type:</th> |         <th>Type:</th> | ||||||
| @@ -60,11 +60,11 @@ export default class NoteInfoWidget extends CollapsibleWidget { | |||||||
|  |  | ||||||
|         this.$noteId.text(note.noteId); |         this.$noteId.text(note.noteId); | ||||||
|         this.$dateCreated |         this.$dateCreated | ||||||
|             .text(noteComplement.dateCreated) |             .text(noteComplement.dateCreated.substr(0, 16)) | ||||||
|             .attr("title", noteComplement.dateCreated); |             .attr("title", noteComplement.dateCreated); | ||||||
|  |  | ||||||
|         this.$dateModified |         this.$dateModified | ||||||
|             .text(noteComplement.dateModified) |             .text(noteComplement.dateModified.substr(0, 16)) | ||||||
|             .attr("title", noteComplement.dateCreated); |             .attr("title", noteComplement.dateCreated); | ||||||
|  |  | ||||||
|         this.$type.text(note.type); |         this.$type.text(note.type); | ||||||
|   | |||||||
| @@ -251,8 +251,8 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|                     this.triggerCommand('setActiveScreen', {screen:'detail'}); |                     this.triggerCommand('setActiveScreen', {screen:'detail'}); | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             expand: (event, data) => this.setExpandedToServer(data.node.data.branchId, true), |             expand: (event, data) => this.setExpanded(data.node.data.branchId, true), | ||||||
|             collapse: (event, data) => this.setExpandedToServer(data.node.data.branchId, false), |             collapse: (event, data) => this.setExpanded(data.node.data.branchId, false), | ||||||
|             hotkeys: utils.isMobile() ? undefined : { keydown: await this.getHotKeys() }, |             hotkeys: utils.isMobile() ? undefined : { keydown: await this.getHotKeys() }, | ||||||
|             dnd5: { |             dnd5: { | ||||||
|                 autoExpandMS: 600, |                 autoExpandMS: 600, | ||||||
| @@ -804,7 +804,9 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|  |  | ||||||
|     async entitiesReloadedEvent({loadResults}) { |     async entitiesReloadedEvent({loadResults}) { | ||||||
|         const activeNode = this.getActiveNode(); |         const activeNode = this.getActiveNode(); | ||||||
|  |         const nextNode = activeNode ? (activeNode.getNextSibling() || activeNode.getPrevSibling() || activeNode.getParent()) : null; | ||||||
|         const activeNotePath = activeNode ? treeService.getNotePath(activeNode) : null; |         const activeNotePath = activeNode ? treeService.getNotePath(activeNode) : null; | ||||||
|  |         const nextNotePath = nextNode ? treeService.getNotePath(nextNode) : null; | ||||||
|         const activeNoteId = activeNode ? activeNode.data.noteId : null; |         const activeNoteId = activeNode ? activeNode.data.noteId : null; | ||||||
|  |  | ||||||
|         const noteIdsToUpdate = new Set(); |         const noteIdsToUpdate = new Set(); | ||||||
| @@ -926,15 +928,27 @@ export default class NoteTreeWidget extends TabAwareWidget { | |||||||
|             if (node) { |             if (node) { | ||||||
|                 node.setActive(true, {noEvents: true}); |                 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); |         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() { |     async reloadTreeFromCache() { | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ const TPL = ` | |||||||
|      |      | ||||||
|     .promoted-attributes td, .promoted-attributes th { |     .promoted-attributes td, .promoted-attributes th { | ||||||
|         padding: 5px; |         padding: 5px; | ||||||
|  |         min-width: 50px; /* otherwise checkboxes can collapse into 0 width (if there are only checkboxes) */ | ||||||
|     } |     } | ||||||
|     </style> |     </style> | ||||||
|      |      | ||||||
| @@ -98,7 +99,7 @@ export default class PromotedAttributesWidget extends TabAwareWidget { | |||||||
|         const $labelCell = $("<th>").append(valueAttr.name); |         const $labelCell = $("<th>").append(valueAttr.name); | ||||||
|         const $input = $("<input>") |         const $input = $("<input>") | ||||||
|             .prop("tabindex", definitionAttr.position) |             .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-type", valueAttr.type) | ||||||
|             .prop("attribute-name", valueAttr.name) |             .prop("attribute-name", valueAttr.name) | ||||||
|             .prop("value", valueAttr.value) |             .prop("value", valueAttr.value) | ||||||
|   | |||||||
| @@ -602,18 +602,23 @@ export default class TabRowWidget extends BasicWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     updateTab($tab, note) { |     updateTab($tab, note) { | ||||||
|         if (!note || !$tab.length) { |         if (!$tab.length) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         this.updateTitle($tab, note.title); |  | ||||||
|  |  | ||||||
|         for (const clazz of Array.from($tab[0].classList)) { // create copy to safely iterate over while removing classes |         for (const clazz of Array.from($tab[0].classList)) { // create copy to safely iterate over while removing classes | ||||||
|             if (clazz !== 'note-tab') { |             if (clazz !== 'note-tab') { | ||||||
|                 $tab.removeClass(clazz); |                 $tab.removeClass(clazz); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (!note) { | ||||||
|  |             this.updateTitle($tab, 'New tab'); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.updateTitle($tab, note.title); | ||||||
|  |  | ||||||
|         $tab.addClass(note.getCssClass()); |         $tab.addClass(note.getCssClass()); | ||||||
|         $tab.addClass(utils.getNoteTypeClass(note.type)); |         $tab.addClass(utils.getNoteTypeClass(note.type)); | ||||||
|         $tab.addClass(utils.getMimeTypeClass(note.mime)); |         $tab.addClass(utils.getMimeTypeClass(note.mime)); | ||||||
|   | |||||||
| @@ -22,6 +22,10 @@ const TPL = ` | |||||||
|     .note-detail-readonly-text p:first-child, .note-detail-text::before { |     .note-detail-readonly-text p:first-child, .note-detail-text::before { | ||||||
|         margin-top: 0; |         margin-top: 0; | ||||||
|     } |     } | ||||||
|  |      | ||||||
|  |     .note-detail-readonly-text img { | ||||||
|  |         max-width: 100%; | ||||||
|  |     } | ||||||
|     </style> |     </style> | ||||||
|  |  | ||||||
|     <div class="alert alert-warning no-print"> |     <div class="alert alert-warning no-print"> | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
|  |  | ||||||
| const noteService = require('../../services/notes'); |  | ||||||
| const protectedSessionService = require('../../services/protected_session'); | const protectedSessionService = require('../../services/protected_session'); | ||||||
| const repository = require('../../services/repository'); | const repository = require('../../services/repository'); | ||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| @@ -45,7 +44,9 @@ async function downloadNoteFile(noteId, res, contentDisposition = true) { | |||||||
|     if (contentDisposition) { |     if (contentDisposition) { | ||||||
|         // (one) reason we're not using the originFileName (available as label) is that it's not |         // (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 |         // 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); |     res.setHeader('Content-Type', note.mime); | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| const repository = require('../../services/repository'); | const repository = require('../../services/repository'); | ||||||
| const noteCacheService = require('../../services/note_cache'); | const noteCacheService = require('../../services/note_cache'); | ||||||
| const protectedSessionService = require('../../services/protected_session'); | const protectedSessionService = require('../../services/protected_session'); | ||||||
|  | const noteRevisionService = require('../../services/note_revisions'); | ||||||
| const utils = require('../../services/utils'); | const utils = require('../../services/utils'); | ||||||
| const path = require('path'); | const path = require('path'); | ||||||
|  |  | ||||||
| @@ -37,13 +38,7 @@ async function getNoteRevision(req) { | |||||||
|  * @return {string} |  * @return {string} | ||||||
|  */ |  */ | ||||||
| function getRevisionFilename(noteRevision) { | function getRevisionFilename(noteRevision) { | ||||||
|     let filename = noteRevision.title || "untitled"; |     let filename = utils.formatDownloadTitle(noteRevision.title, noteRevision.type, noteRevision.mime); | ||||||
|  |  | ||||||
|     if (noteRevision.type === 'text') { |  | ||||||
|         filename += '.html'; |  | ||||||
|     } else if (['relation-map', 'search'].includes(noteRevision.type)) { |  | ||||||
|         filename += '.json'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const extension = path.extname(filename); |     const extension = path.extname(filename); | ||||||
|     const date = noteRevision.dateCreated |     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) { | async function getEditedNotesOnDate(req) { | ||||||
|     const date = utils.sanitizeSql(req.params.date); |     const date = utils.sanitizeSql(req.params.date); | ||||||
|  |  | ||||||
| @@ -141,5 +150,6 @@ module.exports = { | |||||||
|     downloadNoteRevision, |     downloadNoteRevision, | ||||||
|     getEditedNotesOnDate, |     getEditedNotesOnDate, | ||||||
|     eraseAllNoteRevisions, |     eraseAllNoteRevisions, | ||||||
|     eraseNoteRevision |     eraseNoteRevision, | ||||||
|  |     restoreNoteRevision | ||||||
| }; | }; | ||||||
| @@ -145,6 +145,7 @@ function register(app) { | |||||||
|     apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision); |     apiRoute(GET, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.getNoteRevision); | ||||||
|     apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision); |     apiRoute(DELETE, '/api/notes/:noteId/revisions/:noteRevisionId', noteRevisionsApiRoute.eraseNoteRevision); | ||||||
|     route(GET, '/api/notes/:noteId/revisions/:noteRevisionId/download', [auth.checkApiAuthOrElectron], noteRevisionsApiRoute.downloadNoteRevision); |     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(POST, '/api/notes/relation-map', notesApiRoute.getRelationMap); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/change-title', notesApiRoute.changeTitle); |     apiRoute(PUT, '/api/notes/:noteId/change-title', notesApiRoute.changeTitle); | ||||||
|     apiRoute(POST, '/api/notes/:noteId/duplicate/:parentNoteId', notesApiRoute.duplicateNote); |     apiRoute(POST, '/api/notes/:noteId/duplicate/:parentNoteId', notesApiRoute.duplicateNote); | ||||||
|   | |||||||
| @@ -6,9 +6,8 @@ const utils = require('../services/utils'); | |||||||
|  |  | ||||||
| async function setupPage(req, res) { | async function setupPage(req, res) { | ||||||
|     if (await sqlInit.isDbInitialized()) { |     if (await sqlInit.isDbInitialized()) { | ||||||
|         const windowService = require('../services/window'); |  | ||||||
|  |  | ||||||
|         if (utils.isElectron()) { |         if (utils.isElectron()) { | ||||||
|  |             const windowService = require('../services/window'); | ||||||
|             await windowService.createMainWindow(); |             await windowService.createMainWindow(); | ||||||
|             windowService.closeSetupWindow(); |             windowService.closeSetupWindow(); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| module.exports = { buildDate:"2020-05-06T23:24:13+02:00", buildRevision: "54ecd2ee75d1177cedadf9fee10319687feee5f0" }; | module.exports = { buildDate:"2020-05-12T16:46:45+02:00", buildRevision: "4f50864ec8346a12d7845cb4c91a3de3b1043d34" }; | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ const Attribute = require('../entities/attribute'); | |||||||
| const hoistedNoteService = require('../services/hoisted_note'); | const hoistedNoteService = require('../services/hoisted_note'); | ||||||
| const protectedSessionService = require('../services/protected_session'); | const protectedSessionService = require('../services/protected_session'); | ||||||
| const log = require('../services/log'); | const log = require('../services/log'); | ||||||
|  | const utils = require('../services/utils'); | ||||||
| const noteRevisionService = require('../services/note_revisions'); | const noteRevisionService = require('../services/note_revisions'); | ||||||
| const attributeService = require('../services/attributes'); | const attributeService = require('../services/attributes'); | ||||||
| const request = require('./request'); | const request = require('./request'); | ||||||
| @@ -276,9 +277,9 @@ async function downloadImage(noteId, imageUrl) { | |||||||
| const downloadImagePromises = {}; | const downloadImagePromises = {}; | ||||||
|  |  | ||||||
| function replaceUrl(content, url, imageNote) { | 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) { | async function downloadImages(noteId, content) { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| const dayjs = require("dayjs"); | 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; | const smartValueRegex = /^(NOW|TODAY|WEEK|MONTH|YEAR) *([+\-] *\d+)?$/i; | ||||||
|  |  | ||||||
| function calculateSmartValue(v) { | function calculateSmartValue(v) { | ||||||
|   | |||||||
| @@ -221,6 +221,7 @@ async function transactional(func) { | |||||||
|  |  | ||||||
|             await commit(); |             await commit(); | ||||||
|  |  | ||||||
|  |             // note that sync rows sent from this action will be sent again by scheduled periodic ping | ||||||
|             require('./ws.js').sendPingToAllClients(); |             require('./ws.js').sendPingToAllClients(); | ||||||
|  |  | ||||||
|             transactionActive = false; |             transactionActive = false; | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ const randtoken = require('rand-token').generator({source: 'crypto'}); | |||||||
| const unescape = require('unescape'); | const unescape = require('unescape'); | ||||||
| const escape = require('escape-html'); | const escape = require('escape-html'); | ||||||
| const sanitize = require("sanitize-filename"); | const sanitize = require("sanitize-filename"); | ||||||
|  | const mimeTypes = require('mime-types'); | ||||||
|  |  | ||||||
| function newEntityId() { | function newEntityId() { | ||||||
|     return randomString(12); |     return randomString(12); | ||||||
| @@ -166,10 +167,46 @@ function isStringNote(type, mime) { | |||||||
|         || STRING_MIME_TYPES.includes(mime); |         || STRING_MIME_TYPES.includes(mime); | ||||||
| } | } | ||||||
|  |  | ||||||
| function replaceAll(string, replaceWhat, replaceWith) { | function quoteRegex(url) { | ||||||
|     const escapedWhat = replaceWhat.replace(/([\/,!\\^${}\[\]().*+?|<>\-&])/g, "\\$&"); |     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 = { | module.exports = { | ||||||
| @@ -198,5 +235,7 @@ module.exports = { | |||||||
|     sanitizeFilenameForHeader, |     sanitizeFilenameForHeader, | ||||||
|     getContentDisposition, |     getContentDisposition, | ||||||
|     isStringNote, |     isStringNote, | ||||||
|     replaceAll |     quoteRegex, | ||||||
|  |     replaceAll, | ||||||
|  |     formatDownloadTitle | ||||||
| }; | }; | ||||||
| @@ -165,6 +165,5 @@ module.exports = { | |||||||
|     createMainWindow, |     createMainWindow, | ||||||
|     createSetupWindow, |     createSetupWindow, | ||||||
|     closeSetupWindow, |     closeSetupWindow, | ||||||
|     createExtraWindow, |  | ||||||
|     registerGlobalShortcuts |     registerGlobalShortcuts | ||||||
| }; | }; | ||||||
| @@ -5,7 +5,7 @@ | |||||||
|     <link rel="shortcut icon" href="favicon.ico"> |     <link rel="shortcut icon" href="favicon.ico"> | ||||||
|     <title>Trilium Notes</title> |     <title>Trilium Notes</title> | ||||||
| </head> | </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> | <noscript>Trilium requires JavaScript to be enabled.</noscript> | ||||||
|  |  | ||||||
| <div id="toast-container" class="d-flex flex-column justify-content-center align-items-center"></div> | <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"> | <link rel="stylesheet" type="text/css" href="libraries/boxicons/css/boxicons.min.css"> | ||||||
|  |  | ||||||
| <script> |  | ||||||
|     $("body").show(); |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|   | |||||||
| @@ -210,7 +210,7 @@ | |||||||
|  |  | ||||||
| <script src="libraries/knockout.min.js"></script> | <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"> | <link href="stylesheets/themes.css" rel="stylesheet"> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user