mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	Compare commits
	
		
			165 Commits
		
	
	
		
			v0.41.1-be
			...
			v0.43.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a0395e9866 | ||
|  | 89aa4fbc73 | ||
|  | 74a7802088 | ||
|  | a89b6711d1 | ||
|  | b2549b2834 | ||
|  | 959c4cbe64 | ||
|  | d03d3603d2 | ||
|  | e1c2573778 | ||
|  | 2af2b45062 | ||
|  | eabe4775bd | ||
|  | da9b321aa0 | ||
|  | c18d8d2d1b | ||
|  | 5f2361ebd5 | ||
|  | 9791dab97d | ||
|  | 85d986534d | ||
|  | 00faf758e8 | ||
|  | 6ba2e5cf73 | ||
|  | fb3876d28b | ||
|  | fb975849b9 | ||
|  | 16fef78344 | ||
|  | e0b4b369dc | ||
|  | 0df7851214 | ||
|  | 5d47c2b23e | ||
|  | d09b021487 | ||
|  | 910bda860c | ||
|  | 2d92b4931a | ||
|  | 212b719ee9 | ||
|  | 1db892d22f | ||
|  | 535dcb6d12 | ||
|  | 4426362799 | ||
|  | 2c609e8136 | ||
|  | 11b73b79ed | ||
|  | e70c862e72 | ||
|  | b3e66d5a83 | ||
|  | e8cd821e57 | ||
|  | be7ac74235 | ||
|  | 58fa0832f6 | ||
|  | 1502b9ce66 | ||
|  | 7307ca385f | ||
|  | c1fd9825aa | ||
|  | 9de7d3fc53 | ||
|  | 3c5db844ba | ||
|  | e7330c1104 | ||
|  | ec4586b164 | ||
|  | 91e5f24798 | ||
|  | 38723e0189 | ||
|  | 8c88ce6f65 | ||
|  | 4d22959e28 | ||
|  | 50a28d8c51 | ||
|  | e25b633ec4 | ||
|  | 75bd395669 | ||
|  | 5e353a5612 | ||
|  | 6b359b7796 | ||
|  | 13f9d037dc | ||
|  | 1911d64c1c | ||
|  | d4c3f1b3f2 | ||
|  | 3db84daf94 | ||
|  | 2526715aa4 | ||
|  | 04c573e212 | ||
|  | 58f4f5d1e6 | ||
|  | fa5d982a55 | ||
|  | 108afe8896 | ||
|  | 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 | ||
|  | deb0b24c4c | ||
|  | cafcb67a8a | ||
|  | 4c6e9480e4 | ||
|  | 109bead1c7 | ||
|  | ae1220b970 | ||
|  | b89a2df462 | ||
|  | 8b5536ee3a | ||
|  | 647790885d | ||
|  | 227c3e4dcc | ||
|  | 4eb2407c73 | ||
|  | 43e12fbea2 | ||
|  | 2a3091f788 | ||
|  | 742df25bc2 | ||
|  | 9be1d1f697 | ||
|  | ed52f93bbb | ||
|  | 3466a19397 | ||
|  | fe53e2351c | ||
|  | 5c35b870eb | ||
|  | 90d091aedb | ||
|  | 0a05a40186 | ||
|  | 7482ed063b | ||
|  | 70e343f2fc | ||
|  | 358f3a7291 | ||
|  | 6161b1c193 | ||
|  | 94b57dadd7 | ||
|  | 81fbefb9cd | ||
|  | 6d6695e3a9 | ||
|  | 4c308ad68f | ||
|  | 989a003d2f | ||
|  | ccdb41841e | ||
|  | 0a94622413 | ||
|  | 5769587305 | ||
|  | ffbfccb701 | ||
|  | 56ce23fc36 | ||
|  | cba7e5a59f | ||
|  | 86cf8f3202 | ||
|  | 907cdd8fcb | ||
|  | 7ea53d468e | ||
|  | 586d6b4557 | ||
|  | 8f68ff1932 | ||
|  | a1ea2c9115 | ||
|  | e8ce81a133 | ||
|  | aff12950f0 | ||
|  | 75c58cbf79 | ||
|  | 87a1e98fa2 | ||
|  | d1eacbb574 | ||
|  | 71d248cd87 | ||
|  | ac608b9334 | ||
|  | 32020d78b5 | ||
|  | ff853c7d0a | ||
|  | 8526cb2315 | ||
|  | dc89f72e75 | ||
|  | 657ff16267 | ||
|  | ed759f5585 | ||
|  | a86177bb59 | ||
|  | 9f1b3cc892 | ||
|  | 8473f72ec8 | ||
|  | 666d202a3a | ||
|  | 988fae50cb | ||
|  | 98bbd17920 | ||
|  | dadcc93ae3 | ||
|  | 48e19d0149 | ||
|  | f97c9e3619 | ||
|  | 61167f6646 | ||
|  | 29cec8112e | ||
|  | 48aadc8309 | ||
|  | b2508db9af | ||
|  | 87510fd72b | ||
|  | 339f212e4c | ||
|  | 3c311cd2a4 | ||
|  | b5bf581bd9 | ||
|  | 242f139be4 | ||
|  | 6c76d862d2 | ||
|  | 62bc05134e | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| .DS_Store | ||||
| node_modules/ | ||||
| dist/ | ||||
| src/public/app-dist/ | ||||
| npm-debug.log | ||||
| yarn-error.log | ||||
| *.db | ||||
|   | ||||
							
								
								
									
										4
									
								
								.idea/dataSources.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								.idea/dataSources.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,11 +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="document.db" uuid="b0b03187-36c8-4ec1-bdab-fd4273cd692e"> | ||||
|       <driver-ref>sqlite.xerial</driver-ref> | ||||
|       <synchronize>true</synchronize> | ||||
|       <jdbc-driver>org.sqlite.JDBC</jdbc-driver> | ||||
|       <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url> | ||||
|       <jdbc-url>jdbc:sqlite:$USER_HOME$/trilium-data/document.db</jdbc-url> | ||||
|     </data-source> | ||||
|   </component> | ||||
| </project> | ||||
| @@ -1,662 +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.17"> | ||||
|     <root id="1"> | ||||
|       <ServerVersion>3.25.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> | ||||
|       <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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="39" parent="7" name="IDX_attributes_noteId_index"> | ||||
|       <ColNames>noteId</ColNames> | ||||
|     </index> | ||||
|     <index id="40" parent="7" name="IDX_attributes_name_value"> | ||||
|       <ColNames>name | ||||
| value</ColNames> | ||||
|     </index> | ||||
|     <index id="41" parent="7" name="IDX_attributes_value_index"> | ||||
|       <ColNames>value</ColNames> | ||||
|     </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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="55" parent="8" name="IDX_branches_noteId_parentNoteId"> | ||||
|       <ColNames>noteId | ||||
| parentNoteId</ColNames> | ||||
|     </index> | ||||
|     <index id="56" parent="8" name="IDX_branches_parentNoteId"> | ||||
|       <ColNames>parentNoteId</ColNames> | ||||
|     </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> | ||||
|       <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> | ||||
|       <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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="85" parent="11" name="IDX_note_revisions_noteId"> | ||||
|       <ColNames>noteId</ColNames> | ||||
|     </index> | ||||
|     <index id="86" parent="11" name="IDX_note_revisions_utcDateLastEdited"> | ||||
|       <ColNames>utcDateLastEdited</ColNames> | ||||
|     </index> | ||||
|     <index id="87" parent="11" name="IDX_note_revisions_utcDateCreated"> | ||||
|       <ColNames>utcDateCreated</ColNames> | ||||
|     </index> | ||||
|     <index id="88" parent="11" name="IDX_note_revisions_dateLastEdited"> | ||||
|       <ColNames>dateLastEdited</ColNames> | ||||
|     </index> | ||||
|     <index id="89" parent="11" name="IDX_note_revisions_dateCreated"> | ||||
|       <ColNames>dateCreated</ColNames> | ||||
|     </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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="106" parent="12" name="IDX_notes_title"> | ||||
|       <ColNames>title</ColNames> | ||||
|     </index> | ||||
|     <index id="107" parent="12" name="IDX_notes_type"> | ||||
|       <ColNames>type</ColNames> | ||||
|     </index> | ||||
|     <index id="108" parent="12" name="IDX_notes_isDeleted"> | ||||
|       <ColNames>isDeleted</ColNames> | ||||
|     </index> | ||||
|     <index id="109" parent="12" name="IDX_notes_dateCreated"> | ||||
|       <ColNames>dateCreated</ColNames> | ||||
|     </index> | ||||
|     <index id="110" parent="12" name="IDX_notes_dateModified"> | ||||
|       <ColNames>dateModified</ColNames> | ||||
|     </index> | ||||
|     <index id="111" parent="12" name="IDX_notes_utcDateCreated"> | ||||
|       <ColNames>utcDateCreated</ColNames> | ||||
|     </index> | ||||
|     <index id="112" parent="12" name="IDX_notes_utcDateModified"> | ||||
|       <ColNames>utcDateModified</ColNames> | ||||
|     </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> | ||||
|       <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> | ||||
|       <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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="132" parent="15" name="IDX_source_ids_utcDateCreated"> | ||||
|       <ColNames>utcDateCreated</ColNames> | ||||
|     </index> | ||||
|     <key id="133" parent="15"> | ||||
|       <ColNames>sourceId</ColNames> | ||||
|       <Primary>1</Primary> | ||||
|       <UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName> | ||||
|     </key> | ||||
|     <column id="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>int|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> | ||||
|       <Unique>1</Unique> | ||||
|     </index> | ||||
|     <index id="148" parent="18" name="IDX_sync_utcSyncDate"> | ||||
|       <ColNames>utcSyncDate</ColNames> | ||||
|     </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
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +1,7 @@ | ||||
| <component name="InspectionProjectProfileManager"> | ||||
|   <profile version="1.0"> | ||||
|     <option name="myName" value="Project Default" /> | ||||
|     <inspection_tool class="JSUnfilteredForInLoop" enabled="false" level="WARNING" enabled_by_default="false" /> | ||||
|     <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false"> | ||||
|       <option name="processCode" value="true" /> | ||||
|       <option name="processLiterals" value="true" /> | ||||
|   | ||||
							
								
								
									
										1
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							| @@ -2,5 +2,6 @@ | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="" vcs="Git" /> | ||||
|     <mapping directory="$PROJECT_DIR$/../.." vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
| @@ -1,4 +1,4 @@ | ||||
| FROM node:12.16.1-alpine | ||||
| FROM node:12.16.3-alpine | ||||
|  | ||||
| # Create app directory | ||||
| WORKDIR /usr/src/app | ||||
|   | ||||
| @@ -8,7 +8,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l | ||||
| ## Features | ||||
|  | ||||
| * Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes)) | ||||
| * Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-editor#autoformat) | ||||
| * Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-notes#autoformat) | ||||
| * Support for editing [notes with source code](https://github.com/zadam/trilium/wiki/Code-notes), including syntax highlighting | ||||
| * Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation), full text search and [note hoisting](https://github.com/zadam/trilium/wiki/Note-hoisting) | ||||
| * Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions) | ||||
|   | ||||
| @@ -12,6 +12,8 @@ echo "Copying required linux-x64 binaries" | ||||
| rm -r $SRC_DIR/node_modules/sqlite3/lib/binding/* | ||||
| rm -r $SRC_DIR/node_modules/pngquant-bin/vendor/* | ||||
|  | ||||
| rm -r $SRC_DIR/src/public/app-dist/*.mobile.* | ||||
|  | ||||
| cp -r bin/deps/linux-x64/sqlite/* $SRC_DIR/node_modules/sqlite3/lib/binding/ | ||||
| cp bin/deps/linux-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/ | ||||
|  | ||||
| @@ -27,6 +29,9 @@ cp images/app-icons/png/128x128.png $BUILD_DIR/icon.png | ||||
| # removing software WebGL binaries because they are pretty huge and not necessary | ||||
| rm -r $BUILD_DIR/swiftshader | ||||
|  | ||||
| cp bin/tpl/portable-trilium.sh $BUILD_DIR/ | ||||
| chmod 755 $BUILD_DIR/portable-trilium.sh | ||||
|  | ||||
| echo "Packaging linux x64 electron distribution..." | ||||
| VERSION=`jq -r ".version" package.json` | ||||
|  | ||||
|   | ||||
| @@ -19,6 +19,8 @@ cp bin/deps/mac-x64/image/cjpeg $SRC_DIR/node_modules/mozjpeg/vendor/ | ||||
| cp bin/deps/mac-x64/image/pngquant $SRC_DIR/node_modules/pngquant-bin/vendor/ | ||||
| cp bin/deps/mac-x64/image/gifsicle $SRC_DIR/node_modules/giflossy/vendor/ | ||||
|  | ||||
| rm -r $SRC_DIR/src/public/app-dist/*.mobile.* | ||||
|  | ||||
| ./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=images/app-icons/mac/icon.icns | ||||
|  | ||||
| BUILD_DIR=./dist/trilium-mac-x64 | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| PKG_DIR=dist/trilium-linux-x64-server | ||||
| NODE_VERSION=12.16.1 | ||||
| NODE_VERSION=12.16.3 | ||||
|  | ||||
| if [ "$1" != "DONTCOPY" ] | ||||
| then | ||||
|   | ||||
| @@ -19,6 +19,8 @@ cp bin/deps/win-x64/image/cjpeg.exe $SRC_DIR/node_modules/mozjpeg/vendor/ | ||||
| cp bin/deps/win-x64/image/pngquant.exe $SRC_DIR/node_modules/pngquant-bin/vendor/ | ||||
| cp bin/deps/win-x64/image/gifsicle.exe $SRC_DIR/node_modules/giflossy/vendor/ | ||||
|  | ||||
| rm -r $SRC_DIR/src/public/app-dist/*.mobile.* | ||||
|  | ||||
| ./node_modules/.bin/electron-packager $SRC_DIR --asar --out=dist --executable-name=trilium --platform=win32  --arch=x64 --overwrite --icon=images/app-icons/win/icon.ico | ||||
|  | ||||
| BUILD_DIR=./dist/trilium-windows-x64 | ||||
| @@ -29,6 +31,8 @@ mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR | ||||
| # removing software WebGL binaries because they are pretty huge and not necessary | ||||
| rm -r $BUILD_DIR/swiftshader | ||||
|  | ||||
| cp bin/tpl/portable-trilium.bat $BUILD_DIR/ | ||||
|  | ||||
| echo "Zipping windows x64 electron distribution..." | ||||
| VERSION=`jq -r ".version" package.json` | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,8 @@ if [[ $# -eq 0 ]] ; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| npm run webpack | ||||
|  | ||||
| DIR=$1 | ||||
|  | ||||
| rm -rf $DIR | ||||
| @@ -22,8 +24,18 @@ cp -r README.md $DIR/ | ||||
| cp -r LICENSE $DIR/ | ||||
| cp -r config-sample.ini $DIR/ | ||||
| cp -r electron.js $DIR/ | ||||
| cp webpack-* $DIR/ | ||||
|  | ||||
| # run in subshell (so we return to original dir) | ||||
| (cd $DIR && npm install --only=prod) | ||||
|  | ||||
| find $DIR/libraries -name "*.map" -type f -delete | ||||
| find $DIR/libraries -name "*.map" -type f -delete | ||||
|  | ||||
| rm -r $DIR/src/public/app | ||||
|  | ||||
| rm -r $DIR/node_modules/sqlite3/build | ||||
| rm -r $DIR/node_modules/sqlite3/deps | ||||
|  | ||||
| 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\/setup.js/app-dist\/setup.js/g' $DIR/src/views/setup.ejs | ||||
|   | ||||
							
								
								
									
										4
									
								
								bin/tpl/portable-trilium.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								bin/tpl/portable-trilium.bat
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| SET DIR=%~dp0 | ||||
| SET TRILIUM_DATA_DIR=%DIR%\trilium-data | ||||
| cd %DIR% | ||||
| start trilium.exe | ||||
							
								
								
									
										7
									
								
								bin/tpl/portable-trilium.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								bin/tpl/portable-trilium.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #!/usr/bin/env sh | ||||
|  | ||||
| DIR=`dirname "$0"` | ||||
| export TRILIUM_DATA_DIR="$DIR/trilium-data" | ||||
|  | ||||
| "$DIR/trilium" | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								db/demo.zip
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -879,7 +879,7 @@ | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -5483,7 +5483,7 @@ Typical use case is when new note has been created, we should wait until it is s | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -507,7 +507,7 @@ | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -6813,7 +6813,7 @@ Cache is note instance scoped. | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -79,7 +79,7 @@ export default Attribute;</code></pre> | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -81,7 +81,7 @@ export default Branch;</code></pre> | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -61,7 +61,7 @@ export default NoteComplement;</code></pre> | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -493,7 +493,7 @@ export default NoteShort;</code></pre> | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -95,6 +95,275 @@ | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|         <h3 class="subsection-title">Methods</h3> | ||||
|  | ||||
|          | ||||
|              | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <h4 class="name" id="decorateWidget"><span class="type-signature"></span>decorateWidget<span class="signature">()</span><span class="type-signature"></span></h4> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
| <div class="description"> | ||||
|     for overriding | ||||
| </div> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <dl class="details"> | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <dt class="tag-source">Source:</dt> | ||||
|     <dd class="tag-source"><ul class="dummy"><li> | ||||
|         <a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line93">line 93</a> | ||||
|     </li></ul></dd> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
| </dl> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|          | ||||
|              | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <h4 class="name" id="doRenderBody"><span class="type-signature">(async) </span>doRenderBody<span class="signature">()</span><span class="type-signature"></span></h4> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
| <div class="description"> | ||||
|     for overriding | ||||
| </div> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <dl class="details"> | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <dt class="tag-source">Source:</dt> | ||||
|     <dd class="tag-source"><ul class="dummy"><li> | ||||
|         <a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line96">line 96</a> | ||||
|     </li></ul></dd> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
| </dl> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|          | ||||
|              | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <h4 class="name" id="widgetCollapsedStateChangedEvent"><span class="type-signature"></span>widgetCollapsedStateChangedEvent<span class="signature">()</span><span class="type-signature"></span></h4> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
| <div class="description"> | ||||
|     This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered | ||||
| separately but should behave uniformly for the user. | ||||
| </div> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| <dl class="details"> | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|     <dt class="tag-source">Source:</dt> | ||||
|     <dd class="tag-source"><ul class="dummy"><li> | ||||
|         <a href="widgets_collapsible_widget.js.html">widgets/collapsible_widget.js</a>, <a href="widgets_collapsible_widget.js.html#line86">line 86</a> | ||||
|     </li></ul></dd> | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
|  | ||||
|      | ||||
| </dl> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|          | ||||
|      | ||||
|  | ||||
|      | ||||
| @@ -333,7 +602,7 @@ | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -50,7 +50,7 @@ | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
| @@ -443,7 +443,7 @@ export default FrontendScriptApi;</code></pre> | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|   | ||||
							
								
								
									
										151
									
								
								docs/frontend_api/widgets_collapsible_widget.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								docs/frontend_api/widgets_collapsible_widget.js.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <title>JSDoc: Source: widgets/collapsible_widget.js</title> | ||||
|  | ||||
|     <script src="scripts/prettify/prettify.js"> </script> | ||||
|     <script src="scripts/prettify/lang-css.js"> </script> | ||||
|     <!--[if lt IE 9]> | ||||
|       <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> | ||||
|     <![endif]--> | ||||
|     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> | ||||
|     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|  | ||||
| <div id="main"> | ||||
|  | ||||
|     <h1 class="page-title">Source: widgets/collapsible_widget.js</h1> | ||||
|  | ||||
|      | ||||
|  | ||||
|  | ||||
|  | ||||
|      | ||||
|     <section> | ||||
|         <article> | ||||
|             <pre class="prettyprint source linenums"><code>import TabAwareWidget from "./tab_aware_widget.js"; | ||||
| import options from "../services/options.js"; | ||||
|  | ||||
| const WIDGET_TPL = ` | ||||
| <div class="card widget"> | ||||
|     <div class="card-header"> | ||||
|         <div>            | ||||
|             <button class="btn btn-sm widget-title" data-toggle="collapse" data-target="#[to be set]"> | ||||
|                 Collapsible Group Item | ||||
|             </button> | ||||
|              | ||||
|             <a class="widget-help external no-arrow bx bx-info-circle"></a> | ||||
|         </div> | ||||
|          | ||||
|         <div class="widget-header-actions"></div> | ||||
|     </div> | ||||
|  | ||||
|     <div id="[to be set]" class="collapse body-wrapper" style="transition: none; "> | ||||
|         <div class="card-body"></div> | ||||
|     </div> | ||||
| </div>`; | ||||
|  | ||||
| export default class CollapsibleWidget extends TabAwareWidget { | ||||
|     get widgetTitle() { return "Untitled widget"; } | ||||
|  | ||||
|     get headerActions() { return []; } | ||||
|  | ||||
|     get help() { return {}; } | ||||
|  | ||||
|     doRender() { | ||||
|         this.$widget = $(WIDGET_TPL); | ||||
|         this.$widget.find('[data-target]').attr('data-target', "#" + this.componentId); | ||||
|  | ||||
|         this.$bodyWrapper = this.$widget.find('.body-wrapper'); | ||||
|         this.$bodyWrapper.attr('id', this.componentId); // for toggle to work we need id | ||||
|  | ||||
|         this.widgetName = this.constructor.name; | ||||
|  | ||||
|         if (!options.is(this.widgetName + 'Collapsed')) { | ||||
|             this.$bodyWrapper.collapse("show"); | ||||
|         } | ||||
|  | ||||
|         // using immediate variants of the event so that the previous collapse is not caught | ||||
|         this.$bodyWrapper.on('hide.bs.collapse', () => this.saveCollapsed(true)); | ||||
|         this.$bodyWrapper.on('show.bs.collapse', () => this.saveCollapsed(false)); | ||||
|  | ||||
|         this.$body = this.$bodyWrapper.find('.card-body'); | ||||
|  | ||||
|         this.$title = this.$widget.find('.widget-title'); | ||||
|         this.$title.text(this.widgetTitle); | ||||
|  | ||||
|         this.$help = this.$widget.find('.widget-help'); | ||||
|  | ||||
|         if (this.help.title) { | ||||
|             this.$help.attr("title", this.help.title); | ||||
|             this.$help.attr("href", this.help.url || "javascript:"); | ||||
|  | ||||
|             if (!this.help.url) { | ||||
|                 this.$help.addClass('no-link'); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             this.$help.hide(); | ||||
|         } | ||||
|  | ||||
|         this.$headerActions = this.$widget.find('.widget-header-actions'); | ||||
|         this.$headerActions.append(...this.headerActions); | ||||
|  | ||||
|         this.initialized = this.doRenderBody(); | ||||
|  | ||||
|         this.decorateWidget(); | ||||
|  | ||||
|         return this.$widget; | ||||
|     } | ||||
|  | ||||
|     saveCollapsed(collapse) { | ||||
|         options.save(this.widgetName + 'Collapsed', collapse.toString()); | ||||
|  | ||||
|         this.triggerEvent(`widgetCollapsedStateChanged`, {widgetName: this.widgetName, collapse}); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * This event is used to synchronize collapsed state of all the tab-cached widgets since they are all rendered | ||||
|      * separately but should behave uniformly for the user. | ||||
|      */ | ||||
|     widgetCollapsedStateChangedEvent({widgetName, collapse}) { | ||||
|         if (widgetName === this.widgetName) { | ||||
|             this.$bodyWrapper.toggleClass('show', !collapse); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** for overriding */ | ||||
|     decorateWidget() {} | ||||
|  | ||||
|     /** for overriding */ | ||||
|     async doRenderBody() {} | ||||
|  | ||||
|     isExpanded() { | ||||
|         return this.$bodyWrapper.hasClass("show"); | ||||
|     } | ||||
| }</code></pre> | ||||
|         </article> | ||||
|     </section> | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| </div> | ||||
|  | ||||
| <nav> | ||||
|     <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteComplement.html">NoteComplement</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3>Global</h3><ul><li><a href="global.html#decorateWidget">decorateWidget</a></li><li><a href="global.html#doRenderBody">doRenderBody</a></li><li><a href="global.html#widgetCollapsedStateChangedEvent">widgetCollapsedStateChangedEvent</a></li></ul> | ||||
| </nav> | ||||
|  | ||||
| <br class="clear"> | ||||
|  | ||||
| <footer> | ||||
|     Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.4</a> | ||||
| </footer> | ||||
|  | ||||
| <script> prettyPrint(); </script> | ||||
| <script src="scripts/linenumber.js"> </script> | ||||
| </body> | ||||
| </html> | ||||
| @@ -1,4 +1,4 @@ | ||||
| For bug reports, please mention **version of the application** and include **log files** from following location: | ||||
| For bug reports, **PLEASE mention version of Trilium you're using** and also include **log files** from following location: | ||||
|  | ||||
| * `/home/[user]/.local/share/trilium-data/log` for Linux | ||||
| * `C:\Users\[user]\AppData\Roaming\trilium-data\log` for Windows Vista and up | ||||
|   | ||||
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -2986,7 +2986,7 @@ var uniqueId = $.fn.extend( { | ||||
| 				self = this, | ||||
| 				wasExpanded = this.isExpanded(); | ||||
|  | ||||
| 			_assert(this.isLazy(), "load() requires a lazy node"); | ||||
| 			//_assert(this.isLazy(), "load() requires a lazy node"); | ||||
| 			// _assert( forceReload || this.isUndefined(), "Pass forceReload=true to re-load a lazy node" ); | ||||
| 			if (!forceReload && !this.isUndefined()) { | ||||
| 				return _getResolvedPromise(this); | ||||
|   | ||||
							
								
								
									
										2473
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2473
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										37
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								package.json
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.41.1-beta", | ||||
|   "version": "0.43.1", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
| @@ -16,27 +16,28 @@ | ||||
|     "start-server": "TRILIUM_ENV=dev node ./src/www", | ||||
|     "start-electron": "TRILIUM_ENV=dev electron .", | ||||
|     "build-backend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js", | ||||
|     "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js", | ||||
|     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs" | ||||
|     "build-frontend-docs": "./node_modules/.bin/jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/collapsible_widget.js", | ||||
|     "build-docs": "npm run build-backend-docs && npm run build-frontend-docs", | ||||
|     "webpack": "npx webpack -c webpack-desktop.config.js && npx webpack -c webpack-mobile.config.js && npx webpack -c webpack-setup.config.js" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "async-mutex": "0.2.1", | ||||
|     "async-mutex": "0.2.2", | ||||
|     "axios": "0.19.2", | ||||
|     "body-parser": "1.19.0", | ||||
|     "cls-hooked": "4.2.2", | ||||
|     "commonmark": "0.29.1", | ||||
|     "cookie-parser": "1.4.5", | ||||
|     "csurf": "1.11.0", | ||||
|     "dayjs": "1.8.23", | ||||
|     "dayjs": "1.8.26", | ||||
|     "debug": "4.1.1", | ||||
|     "ejs": "3.0.2", | ||||
|     "ejs": "3.1.2", | ||||
|     "electron-debug": "3.0.1", | ||||
|     "electron-dl": "3.0.0", | ||||
|     "electron-find": "1.0.6", | ||||
|     "electron-window-state": "5.0.3", | ||||
|     "express": "4.17.1", | ||||
|     "express-session": "1.17.0", | ||||
|     "file-type": "14.1.4", | ||||
|     "express-session": "1.17.1", | ||||
|     "file-type": "14.3.0", | ||||
|     "fs-extra": "9.0.0", | ||||
|     "helmet": "3.22.0", | ||||
|     "html": "1.0.0", | ||||
| @@ -50,10 +51,10 @@ | ||||
|     "imagemin-pngquant": "8.0.0", | ||||
|     "ini": "1.3.5", | ||||
|     "is-svg": "4.2.1", | ||||
|     "jimp": "0.10.1", | ||||
|     "mime-types": "2.1.26", | ||||
|     "jimp": "0.10.3", | ||||
|     "mime-types": "2.1.27", | ||||
|     "multer": "1.4.2", | ||||
|     "node-abi": "2.15.0", | ||||
|     "node-abi": "2.16.0", | ||||
|     "open": "7.0.3", | ||||
|     "portscanner": "2.2.0", | ||||
|     "rand-token": "1.0.1", | ||||
| @@ -61,28 +62,30 @@ | ||||
|     "rimraf": "3.0.2", | ||||
|     "sanitize-filename": "1.6.3", | ||||
|     "sax": "1.2.4", | ||||
|     "semver": "7.2.1", | ||||
|     "semver": "7.3.2", | ||||
|     "serve-favicon": "2.5.0", | ||||
|     "session-file-store": "1.4.0", | ||||
|     "simple-node-logger": "18.12.24", | ||||
|     "sqlite": "3.0.6", | ||||
|     "sqlite": "4.0.7", | ||||
|     "sqlite3": "4.1.1", | ||||
|     "string-similarity": "4.0.1", | ||||
|     "tar-stream": "2.1.2", | ||||
|     "turndown": "6.0.0", | ||||
|     "turndown-plugin-gfm": "1.0.2", | ||||
|     "unescape": "1.0.1", | ||||
|     "ws": "7.2.3", | ||||
|     "ws": "7.2.5", | ||||
|     "yauzl": "^2.10.0", | ||||
|     "yazl": "^2.5.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "electron": "9.0.0-beta.14", | ||||
|     "electron-builder": "22.4.1", | ||||
|     "electron": "9.0.5", | ||||
|     "electron-builder": "22.6.0", | ||||
|     "electron-packager": "14.2.1", | ||||
|     "electron-rebuild": "1.10.1", | ||||
|     "jsdoc": "3.6.4", | ||||
|     "lorem-ipsum": "2.0.3" | ||||
|     "lorem-ipsum": "2.0.3", | ||||
|     "webpack": "5.0.0-beta.16", | ||||
|     "webpack-cli": "4.0.0-beta.8" | ||||
|   }, | ||||
|   "optionalDependencies": { | ||||
|     "electron-installer-debian": "2.0.1" | ||||
|   | ||||
| @@ -1,7 +1,24 @@ | ||||
| const anonymizationService = require('./services/anonymization'); | ||||
| const backupService = require('./services/backup'); | ||||
| const sqlInit = require('./services/sql_init'); | ||||
| require('./entities/entity_constructor'); | ||||
|  | ||||
| anonymizationService.anonymize().then(filePath => { | ||||
|     console.log("Anonymized file has been saved to:", filePath); | ||||
| sqlInit.dbReady.then(async () => { | ||||
|     try { | ||||
|         console.log("Starting anonymization..."); | ||||
|  | ||||
|     process.exit(0); | ||||
| }); | ||||
|         const resp = await backupService.anonymize(); | ||||
|  | ||||
|         if (resp.success) { | ||||
|             console.log("Anonymized file has been saved to: " + resp.anonymizedFilePath); | ||||
|  | ||||
|             process.exit(0); | ||||
|         } else { | ||||
|             console.log("Anonymization failed."); | ||||
|         } | ||||
|     } | ||||
|     catch (e) { | ||||
|         console.error(e.message, e.stack); | ||||
|     } | ||||
|  | ||||
|     process.exit(1); | ||||
| }); | ||||
|   | ||||
							
								
								
									
										13
									
								
								src/app.js
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/app.js
									
									
									
									
									
								
							| @@ -28,17 +28,6 @@ app.use((req, res, next) => { | ||||
|     next(); | ||||
| }); | ||||
|  | ||||
| app.use((req, res, next) => { | ||||
|     cls.namespace.bindEmitter(req); | ||||
|     cls.namespace.bindEmitter(res); | ||||
|  | ||||
|     cls.init(() => { | ||||
|         cls.namespace.set("Hi"); | ||||
|  | ||||
|         next(); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| app.use(bodyParser.json({limit: '500mb'})); | ||||
| app.use(bodyParser.urlencoded({extended: false})); | ||||
| app.use(cookieParser()); | ||||
| @@ -120,4 +109,4 @@ require('./services/scheduler'); | ||||
| module.exports = { | ||||
|     app, | ||||
|     sessionParser | ||||
| }; | ||||
| }; | ||||
|   | ||||
| @@ -105,8 +105,7 @@ class Attribute extends Entity { | ||||
|  | ||||
|     // cannot be static! | ||||
|     updatePojo(pojo) { | ||||
|         delete pojo.isOwned; | ||||
|         delete pojo.__note; | ||||
|         delete pojo.__note; // FIXME: probably note necessary anymore | ||||
|     } | ||||
|  | ||||
|     createClone(type, name, value) { | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
| @@ -545,12 +541,13 @@ class Note extends Entity { | ||||
|     /** | ||||
|      * @return {Promise<Attribute>} | ||||
|      */ | ||||
|     async addAttribute(type, name, value = "") { | ||||
|     async addAttribute(type, name, value = "", isInheritable = false) { | ||||
|         const attr = new Attribute({ | ||||
|             noteId: this.noteId, | ||||
|             type: type, | ||||
|             name: name, | ||||
|             value: value | ||||
|             value: value, | ||||
|             isInheritable: isInheritable | ||||
|         }); | ||||
|  | ||||
|         await attr.save(); | ||||
| @@ -560,12 +557,12 @@ class Note extends Entity { | ||||
|         return attr; | ||||
|     } | ||||
|  | ||||
|     async addLabel(name, value = "") { | ||||
|         return await this.addAttribute(LABEL, name, value); | ||||
|     async addLabel(name, value = "", isInheritable = false) { | ||||
|         return await this.addAttribute(LABEL, name, value, isInheritable); | ||||
|     } | ||||
|  | ||||
|     async addRelation(name, targetNoteId) { | ||||
|         return await this.addAttribute(RELATION, name, targetNoteId); | ||||
|     async addRelation(name, targetNoteId, isInheritable = false) { | ||||
|         return await this.addAttribute(RELATION, name, targetNoteId, isInheritable); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -946,4 +943,4 @@ class Note extends Entity { | ||||
|     } | ||||
| } | ||||
|  | ||||
| module.exports = Note; | ||||
| module.exports = Note; | ||||
|   | ||||
| @@ -1,76 +1,19 @@ | ||||
| import glob from './services/glob.js'; | ||||
| import link from './services/link.js'; | ||||
| import ws from './services/ws.js'; | ||||
| import noteType from './widgets/note_type.js'; | ||||
| import protectedSessionService from './services/protected_session.js'; | ||||
| import protectedSessionHolder from './services/protected_session_holder.js'; | ||||
| import FrontendScriptApi from './services/frontend_script_api.js'; | ||||
| import ScriptContext from './services/script_context.js'; | ||||
| import sync from './services/sync.js'; | ||||
| import treeService from './services/tree.js'; | ||||
| import branchService from './services/branches.js'; | ||||
| import appContext from "./services/app_context.js"; | ||||
| import utils from './services/utils.js'; | ||||
| import server from './services/server.js'; | ||||
| import Entrypoints from './services/entrypoints.js'; | ||||
| import noteTooltipService from './services/note_tooltip.js'; | ||||
| import bundle from "./services/bundle.js"; | ||||
| import treeCache from "./services/tree_cache.js"; | ||||
| import libraryLoader from "./services/library_loader.js"; | ||||
| import hoistedNoteService from './services/hoisted_note.js'; | ||||
| import noteTypeService from './widgets/note_type.js'; | ||||
| import linkService from './services/link.js'; | ||||
| import bundleService from "./services/bundle.js"; | ||||
| import noteAutocompleteService from './services/note_autocomplete.js'; | ||||
| import macInit from './services/mac_init.js'; | ||||
| import dateNoteService from './services/date_notes.js'; | ||||
| import importService from './services/import.js'; | ||||
| import keyboardActionService from "./services/keyboard_actions.js"; | ||||
| import splitService from "./services/split.js"; | ||||
| import options from "./services/options.js"; | ||||
| import noteContentRenderer from "./services/note_content_renderer.js"; | ||||
| import appContext from "./services/app_context.js"; | ||||
| import FlexContainer from "./widgets/flex_container.js"; | ||||
| import GlobalMenuWidget from "./widgets/global_menu.js"; | ||||
| import TabRowWidget from "./widgets/tab_row.js"; | ||||
| import TitleBarButtonsWidget from "./widgets/title_bar_buttons.js"; | ||||
| import StandardTopWidget from "./widgets/standard_top_widget.js"; | ||||
| import SidePaneContainer from "./widgets/side_pane_container.js"; | ||||
| import GlobalButtonsWidget from "./widgets/global_buttons.js"; | ||||
| import SearchBoxWidget from "./widgets/search_box.js"; | ||||
| import SearchResultsWidget from "./widgets/search_results.js"; | ||||
| import NoteTreeWidget from "./widgets/note_tree.js"; | ||||
| import TabCachingWidget from "./widgets/tab_caching_widget.js"; | ||||
| import NotePathsWidget from "./widgets/note_paths.js"; | ||||
| import NoteTitleWidget from "./widgets/note_title.js"; | ||||
| import RunScriptButtonsWidget from "./widgets/run_script_buttons.js"; | ||||
| import ProtectedNoteSwitchWidget from "./widgets/protected_note_switch.js"; | ||||
| import NoteTypeWidget from "./widgets/note_type.js"; | ||||
| import NoteActionsWidget from "./widgets/note_actions.js"; | ||||
| import PromotedAttributesWidget from "./widgets/promoted_attributes.js"; | ||||
| import NoteDetailWidget from "./widgets/note_detail.js"; | ||||
| import NoteInfoWidget from "./widgets/note_info.js"; | ||||
| import CalendarWidget from "./widgets/calendar.js"; | ||||
| import AttributesWidget from "./widgets/attributes.js"; | ||||
| import LinkMapWidget from "./widgets/link_map.js"; | ||||
| import NoteRevisionsWidget from "./widgets/note_revisions.js"; | ||||
| import SimilarNotesWidget from "./widgets/similar_notes.js"; | ||||
| import WhatLinksHereWidget from "./widgets/what_links_here.js"; | ||||
| import SidePaneToggles from "./widgets/side_pane_toggles.js"; | ||||
| import EmptyTypeWidget from "./widgets/type_widgets/empty.js"; | ||||
| import TextTypeWidget from "./widgets/type_widgets/editable_text.js"; | ||||
| import CodeTypeWidget from "./widgets/type_widgets/code.js"; | ||||
| import FileTypeWidget from "./widgets/type_widgets/file.js"; | ||||
| import ImageTypeWidget from "./widgets/type_widgets/image.js"; | ||||
| import SearchTypeWidget from "./widgets/type_widgets/search.js"; | ||||
| import RenderTypeWidget from "./widgets/type_widgets/render.js"; | ||||
| import RelationMapTypeWidget from "./widgets/type_widgets/relation_map.js"; | ||||
| import ProtectedSessionTypeWidget from "./widgets/type_widgets/protected_session.js"; | ||||
| import BookTypeWidget from "./widgets/type_widgets/book.js"; | ||||
| import contextMenu from "./services/context_menu.js"; | ||||
| import DesktopLayout from "./widgets/desktop_layout.js"; | ||||
| import bundleService from "./services/bundle.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(); | ||||
| 
 | ||||
| if (utils.isElectron()) { | ||||
|     require('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) { | ||||
|     utils.dynamicRequire('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) { | ||||
|         appContext.triggerCommand(actionName); | ||||
|     }); | ||||
| } | ||||
| @@ -82,9 +25,11 @@ $('[data-toggle="tooltip"]').tooltip({ | ||||
| macInit.init(); | ||||
| 
 | ||||
| bundleService.getWidgetBundlesByParent().then(widgetBundles => { | ||||
|     const desktopLayout = new DesktopLayout(widgetBundles); | ||||
|     const layout = window.glob.isMainWindow | ||||
|         ? new DesktopMainWindowLayout(widgetBundles) | ||||
|         : new DesktopExtraWindowLayout(widgetBundles); | ||||
| 
 | ||||
|     appContext.setLayout(desktopLayout); | ||||
|     appContext.setLayout(layout); | ||||
|     appContext.start(); | ||||
| }); | ||||
| 
 | ||||
| @@ -93,7 +38,7 @@ noteTooltipService.setupGlobalTooltip(); | ||||
| noteAutocompleteService.init(); | ||||
| 
 | ||||
| if (utils.isElectron()) { | ||||
|     const electron = require('electron'); | ||||
|     const electron = utils.dynamicRequire('electron'); | ||||
|     const {webContents} = electron.remote.getCurrentWindow(); | ||||
| 
 | ||||
|     webContents.on('context-menu', (event, params) => { | ||||
| @@ -141,7 +86,7 @@ if (utils.isElectron()) { | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         if (params.linkURL.length !== 0 && params.mediaType === 'none') { | ||||
|         if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === 'none') { | ||||
|             items.push({ | ||||
|                 title: `Copy link`, | ||||
|                 uiIcon: "copy", | ||||
| @@ -189,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') { | ||||
| @@ -200,4 +147,4 @@ if (utils.isElectron()) { | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
| } | ||||
| @@ -20,6 +20,14 @@ export async function showDialog(widget) { | ||||
|     updateTitleFormGroupVisibility(); | ||||
|     $addLinkTitleSettings.find('input[type=radio]').on('change', updateTitleFormGroupVisibility); | ||||
| 
 | ||||
|     // with selection hyper link is implied
 | ||||
|     if (textTypeWidget.hasSelection()) { | ||||
|         $addLinkTitleSettings.find("input[value='hyper-link']").prop("checked", true); | ||||
|     } | ||||
|     else { | ||||
|         $addLinkTitleSettings.find("input[value='reference-link']").prop("checked", true); | ||||
|     } | ||||
| 
 | ||||
|     utils.openDialog($dialog); | ||||
| 
 | ||||
|     $autoComplete.val('').trigger('focus'); | ||||
| @@ -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); | ||||
| @@ -152,10 +152,10 @@ function AttributesModel() { | ||||
|                 attr.value = treeService.getNoteIdFromNotePath(attr.selectedPath); | ||||
|             } | ||||
|             else if (attr.type === 'label-definition') { | ||||
|                 attr.value = attr.labelDefinition; | ||||
|                 attr.value = JSON.stringify(attr.labelDefinition); | ||||
|             } | ||||
|             else if (attr.type === 'relation-definition') { | ||||
|                 attr.value = attr.relationDefinition; | ||||
|                 attr.value = JSON.stringify(attr.relationDefinition); | ||||
|             } | ||||
| 
 | ||||
|             delete attr.labelValue; | ||||
| @@ -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 | ||||
|     }) | ||||
| }); | ||||
| }); | ||||
| @@ -39,13 +39,14 @@ export async function showDialog(noteIds) { | ||||
| } | ||||
| 
 | ||||
| async function cloneNotesTo(notePath) { | ||||
|     const targetNoteId = treeService.getNoteIdFromNotePath(notePath); | ||||
|     const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath); | ||||
|     const targetBranchId = await treeCache.getBranchId(parentNoteId, noteId); | ||||
| 
 | ||||
|     for (const cloneNoteId of clonedNoteIds) { | ||||
|         await branchService.cloneNoteTo(cloneNoteId, targetNoteId, $clonePrefix.val()); | ||||
|         await branchService.cloneNoteTo(cloneNoteId, targetBranchId, $clonePrefix.val()); | ||||
| 
 | ||||
|         const clonedNote = await treeCache.getNote(cloneNoteId); | ||||
|         const targetNote = await treeCache.getNote(targetNoteId); | ||||
|         const targetNote = await treeCache.getBranch(targetBranchId).getNote(); | ||||
| 
 | ||||
|         toastService.showMessage(`Note "${clonedNote.title}" has been cloned into ${targetNote.title}`); | ||||
|     } | ||||
| @@ -64,4 +65,4 @@ $form.on('submit', () => { | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| }); | ||||
| }); | ||||
| @@ -25,13 +25,15 @@ async function includeNote(notePath) { | ||||
|     const noteId = treeService.getNoteIdFromNotePath(notePath); | ||||
|     const note = await treeCache.getNote(noteId); | ||||
| 
 | ||||
|     const boxSize = $("input[name='include-note-box-size']:checked").val(); | ||||
| 
 | ||||
|     if (note.type === 'image') { | ||||
|         // there's no benefit to use insert note functionlity for images
 | ||||
|         // so we'll just add an IMG tag
 | ||||
|         textTypeWidget.addImage(noteId); | ||||
|     } | ||||
|     else { | ||||
|         textTypeWidget.addIncludeNote(noteId); | ||||
|         textTypeWidget.addIncludeNote(noteId, boxSize); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @@ -34,7 +34,7 @@ export async function importMarkdownInline() { | ||||
|     } | ||||
| 
 | ||||
|     if (utils.isElectron()) { | ||||
|         const {clipboard} = require('electron'); | ||||
|         const {clipboard} = utils.dynamicRequire('electron'); | ||||
|         const text = clipboard.readText(); | ||||
| 
 | ||||
|         convertMarkdownToHtml(text); | ||||
| @@ -32,10 +32,11 @@ export async function showDialog(branchIds) { | ||||
|     noteAutocompleteService.showRecentNotes($noteAutoComplete); | ||||
| } | ||||
| 
 | ||||
| async function moveNotesTo(parentNoteId) { | ||||
|     await branchService.moveToParentNote(movedBranchIds, parentNoteId); | ||||
| async function moveNotesTo(parentBranchId) { | ||||
|     await branchService.moveToParentNote(movedBranchIds, parentBranchId); | ||||
| 
 | ||||
|     const parentNote = await treeCache.getNote(parentNoteId); | ||||
|     const parentBranch = treeCache.getBranch(parentBranchId); | ||||
|     const parentNote = await parentBranch.getNote(); | ||||
| 
 | ||||
|     toastService.showMessage(`Selected notes have been moved into ${parentNote.title}`); | ||||
| } | ||||
| @@ -46,13 +47,12 @@ $form.on('submit', () => { | ||||
|     if (notePath) { | ||||
|         $dialog.modal('hide'); | ||||
| 
 | ||||
|         const noteId = treeService.getNoteIdFromNotePath(notePath); | ||||
| 
 | ||||
|         moveNotesTo(noteId); | ||||
|         const {noteId, parentNoteId} = treeService.getNoteIdAndParentIdFromNotePath(notePath); | ||||
|         treeCache.getBranchId(parentNoteId, noteId).then(branchId => moveNotesTo(branchId)); | ||||
|     } | ||||
|     else { | ||||
|         console.error("No path to move to."); | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| }); | ||||
| }); | ||||
| @@ -37,14 +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)); | ||||
|         $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'); | ||||
| @@ -59,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', () => { | ||||
| @@ -76,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 () => { | ||||
| @@ -92,6 +113,8 @@ async function setContentPane() { | ||||
|     }); | ||||
| 
 | ||||
|     $titleButtons | ||||
|         .append($restoreRevisionButton) | ||||
|         .append('   ') | ||||
|         .append($eraseRevisionButton) | ||||
|         .append('   '); | ||||
| 
 | ||||
| @@ -17,12 +17,18 @@ const TPL = ` | ||||
| 
 | ||||
| <button id="find-and-fix-consistency-issues-button" class="btn">Find and fix consistency issues</button><br/><br/> | ||||
| 
 | ||||
| <h4>Debugging</h4> | ||||
| <h4>Anonymize database</h4> | ||||
| 
 | ||||
| <p>This action will create a new copy of the database and anonymise it (remove all note content and leave only structure and some non-sensitive metadata) | ||||
|     for sharing online for debugging purposes without fear of leaking your personal data.</p> | ||||
| 
 | ||||
| <button id="anonymize-button" class="btn">Save anonymized database</button><br/><br/> | ||||
| 
 | ||||
| <p>This action will create a new copy of the database and anonymise it (remove all note content and leave only structure and metadata) | ||||
|     for sharing online for debugging purposes without fear of leaking your personal data.</p> | ||||
| <h4>Backup database</h4> | ||||
| 
 | ||||
| <p>Trilium has automatic backup (daily, weekly, monthly), but you can also trigger backup manually here.</p> | ||||
| 
 | ||||
| <button id="backup-database-button" class="btn">Backup database now</button><br/><br/> | ||||
| 
 | ||||
| <h4>Vacuum database</h4> | ||||
| 
 | ||||
| @@ -37,6 +43,7 @@ export default class AdvancedOptions { | ||||
|         this.$forceFullSyncButton = $("#force-full-sync-button"); | ||||
|         this.$fillSyncRowsButton = $("#fill-sync-rows-button"); | ||||
|         this.$anonymizeButton = $("#anonymize-button"); | ||||
|         this.$backupDatabaseButton = $("#backup-database-button"); | ||||
|         this.$vacuumDatabaseButton = $("#vacuum-database-button"); | ||||
|         this.$findAndFixConsistencyIssuesButton = $("#find-and-fix-consistency-issues-button"); | ||||
| 
 | ||||
| @@ -53,21 +60,32 @@ export default class AdvancedOptions { | ||||
|         }); | ||||
| 
 | ||||
|         this.$anonymizeButton.on('click', async () => { | ||||
|             await server.post('anonymization/anonymize'); | ||||
|             const resp = await server.post('database/anonymize'); | ||||
| 
 | ||||
|             toastService.showMessage("Created anonymized database"); | ||||
|             if (!resp.success) { | ||||
|                 toastService.showError("Could not create anonymized database, check backend logs for details"); | ||||
|             } | ||||
|             else { | ||||
|                 toastService.showMessage(`Created anonymized database in ${resp.anonymizedFilePath}`, 10000); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         this.$backupDatabaseButton.on('click', async () => { | ||||
|             const {backupFile} = await server.post('database/backup-database'); | ||||
| 
 | ||||
|             toastService.showMessage("Database has been backed up to " + backupFile, 10000); | ||||
|         }); | ||||
| 
 | ||||
|         this.$vacuumDatabaseButton.on('click', async () => { | ||||
|             await server.post('cleanup/vacuum-database'); | ||||
|             await server.post('database/vacuum-database'); | ||||
| 
 | ||||
|             toastService.showMessage("Database has been vacuumed"); | ||||
|         }); | ||||
| 
 | ||||
|         this.$findAndFixConsistencyIssuesButton.on('click', async () => { | ||||
|             await server.post('cleanup/find-and-fix-consistency-issues'); | ||||
|             await server.post('database/find-and-fix-consistency-issues'); | ||||
| 
 | ||||
|             toastService.showMessage("Consistency issues should be fixed."); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| import optionsService from "../../services/options.js"; | ||||
| import utils from "../../services/utils.js"; | ||||
| import server from "../../services/server.js"; | ||||
| import toastService from "../../services/toast.js"; | ||||
| 
 | ||||
| @@ -20,7 +20,9 @@ const TPL = ` | ||||
|         <input type="text" class="form-control" id="spell-check-language-code" placeholder="for example "en-US", "de-AT""> | ||||
|     </div> | ||||
| 
 | ||||
|     <p>Multiple languages can be separated by comman. Changes to the spell check options will take effect after application restart.</p> | ||||
|     <p>Multiple languages can be separated by comma, e.g. <code>en-US, de-DE, cs</code>. Changes to the spell check options will take effect after application restart.</p> | ||||
|      | ||||
|     <p><strong>Available language codes: </strong> <span id="available-language-codes"></span></p> | ||||
| </div> | ||||
| 
 | ||||
| <div> | ||||
| @@ -95,6 +97,14 @@ export default class ProtectedSessionOptions { | ||||
|             return false; | ||||
|         }); | ||||
| 
 | ||||
|         this.$availableLanguageCodes = $("#available-language-codes"); | ||||
| 
 | ||||
|         if (utils.isElectron()) { | ||||
|             const {webContents} = utils.dynamicRequire('electron').remote.getCurrentWindow(); | ||||
| 
 | ||||
|             this.$availableLanguageCodes.text(webContents.session.availableSpellCheckerLanguages.join(', ')); | ||||
|         } | ||||
| 
 | ||||
|         this.$eraseNotesAfterTimeInSeconds = $("#erase-notes-after-time-in-seconds"); | ||||
| 
 | ||||
|         this.$eraseNotesAfterTimeInSeconds.on('change', () => { | ||||
| @@ -16,26 +16,26 @@ export async function showDialog(ancestorNoteId) { | ||||
|         ancestorNoteId = hoistedNoteService.getHoistedNoteId(); | ||||
|     } | ||||
| 
 | ||||
|     const result = await server.get('recent-changes/' + ancestorNoteId); | ||||
|     const recentChangesRows = await server.get('recent-changes/' + ancestorNoteId); | ||||
| 
 | ||||
|     // preload all notes into cache
 | ||||
|     await treeCache.getNotes(result.map(r => r.noteId), true); | ||||
|     await treeCache.getNotes(recentChangesRows.map(r => r.noteId), true); | ||||
| 
 | ||||
|     $content.empty(); | ||||
| 
 | ||||
|     if (result.length === 0) { | ||||
|     if (recentChangesRows.length === 0) { | ||||
|         $content.append("No changes yet ..."); | ||||
|     } | ||||
| 
 | ||||
|     const groupedByDate = groupByDate(result); | ||||
|     const groupedByDate = groupByDate(recentChangesRows); | ||||
| 
 | ||||
|     for (const [dateDay, dayChanges] of groupedByDate) { | ||||
|         const $changesList = $('<ul>'); | ||||
| 
 | ||||
|         const dayEl = $('<div>').append($('<b>').html(utils.formatDate(dateDay))).append($changesList); | ||||
|         const dayEl = $('<div>').append($('<b>').text(dateDay)).append($changesList); | ||||
| 
 | ||||
|         for (const change of dayChanges) { | ||||
|             const formattedTime = utils.formatTime(utils.parseDate(change.date)); | ||||
|             const formattedTime = change.date.substr(11, 5); | ||||
| 
 | ||||
|             let $noteLink; | ||||
| 
 | ||||
| @@ -82,7 +82,12 @@ export async function showDialog(ancestorNoteId) { | ||||
|             } | ||||
| 
 | ||||
|             $changesList.append($('<li>') | ||||
|                 .append(formattedTime + ' - ') | ||||
|                 .append( | ||||
|                     $("<span>") | ||||
|                         .text(formattedTime) | ||||
|                         .attr("title", change.date) | ||||
|                 ) | ||||
|                 .append(' - ') | ||||
|                 .append($noteLink)); | ||||
|         } | ||||
| 
 | ||||
| @@ -90,25 +95,11 @@ export async function showDialog(ancestorNoteId) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function groupByDate(result) { | ||||
| function groupByDate(rows) { | ||||
|     const groupedByDate = new Map(); | ||||
|     const dayCache = {}; | ||||
| 
 | ||||
|     for (const row of result) { | ||||
|         let dateDay = utils.parseDate(row.date); | ||||
|         dateDay.setHours(0); | ||||
|         dateDay.setMinutes(0); | ||||
|         dateDay.setSeconds(0); | ||||
|         dateDay.setMilliseconds(0); | ||||
| 
 | ||||
|         // this stupidity is to make sure that we always use the same day object because Map uses only
 | ||||
|         // reference equality
 | ||||
|         if (dayCache[dateDay]) { | ||||
|             dateDay = dayCache[dateDay]; | ||||
|         } | ||||
|         else { | ||||
|             dayCache[dateDay] = dateDay; | ||||
|         } | ||||
|     for (const row of rows) { | ||||
|         const dateDay = row.date.substr(0, 10); | ||||
| 
 | ||||
|         if (!groupedByDate.has(dateDay)) { | ||||
|             groupedByDate.set(dateDay, []); | ||||
							
								
								
									
										76
									
								
								src/public/app/entities/attribute.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/public/app/entities/attribute.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| class Attribute { | ||||
|     constructor(treeCache, row) { | ||||
|         this.treeCache = treeCache; | ||||
|  | ||||
|         this.update(row); | ||||
|     } | ||||
|  | ||||
|     update(row) { | ||||
|         /** @param {string} attributeId */ | ||||
|         this.attributeId = row.attributeId; | ||||
|         /** @param {string} noteId */ | ||||
|         this.noteId = row.noteId; | ||||
|         /** @param {string} type */ | ||||
|         this.type = row.type; | ||||
|         /** @param {string} name */ | ||||
|         this.name = row.name; | ||||
|         /** @param {string} value */ | ||||
|         this.value = row.value; | ||||
|         /** @param {int} position */ | ||||
|         this.position = row.position; | ||||
|         /** @param {boolean} isInheritable */ | ||||
|         this.isInheritable = row.isInheritable; | ||||
|     } | ||||
|  | ||||
|     /** @returns {NoteShort} */ | ||||
|     getNote() { | ||||
|         return this.treeCache.notes[this.noteId]; | ||||
|     } | ||||
|  | ||||
|     get targetNoteId() { // alias | ||||
|         return this.type === 'relation' ? this.value : undefined; | ||||
|     } | ||||
|  | ||||
|     get jsonValue() { | ||||
|         try { | ||||
|             return JSON.parse(this.value); | ||||
|         } | ||||
|         catch (e) { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     get toString() { | ||||
|         return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name}, value=${this.value})`; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return {boolean} - returns true if this attribute has the potential to influence the note in the argument. | ||||
|      *         That can happen in multiple ways: | ||||
|      *         1. attribute is owned by the note | ||||
|      *         2. attribute is owned by the template of the note | ||||
|      *         3. attribute is owned by some note's ancestor and is inheritable | ||||
|      */ | ||||
|     isAffecting(affectedNote) { | ||||
|         const attrNote = this.getNote(); | ||||
|         const owningNotes = [affectedNote, ...affectedNote.getTemplateNotes()]; | ||||
|  | ||||
|         for (const owningNote of owningNotes) { | ||||
|             if (owningNote.noteId === attrNote.noteId) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (this.isInheritable) { | ||||
|             for (const owningNote of owningNotes) { | ||||
|                 if (owningNote.hasAncestor(attrNote)) { | ||||
|                     return true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| export default Attribute; | ||||
| @@ -1,5 +1,6 @@ | ||||
| import server from '../services/server.js'; | ||||
| import Attribute from './attribute.js'; | ||||
| import noteAttributeCache from "../services/note_attribute_cache.js"; | ||||
| 
 | ||||
| const LABEL = 'label'; | ||||
| const LABEL_DEFINITION = 'label-definition'; | ||||
| @@ -7,6 +8,8 @@ const RELATION = 'relation'; | ||||
| const RELATION_DEFINITION = 'relation-definition'; | ||||
| 
 | ||||
| /** | ||||
|  * FIXME: since there's no "full note" anymore we can rename this to Note | ||||
|  * | ||||
|  * This note's representation is used in note tree and is kept in TreeCache. | ||||
|  */ | ||||
| class NoteShort { | ||||
| @@ -156,9 +159,9 @@ class NoteShort { | ||||
|     getOwnedAttributes(type, name) { | ||||
|         const attrs = this.attributes | ||||
|             .map(attributeId => this.treeCache.attributes[attributeId]) | ||||
|             .filter(attr => !!attr); | ||||
|             .filter(Boolean); // filter out nulls;
 | ||||
| 
 | ||||
|         return this.__filterAttrs(attrs, type, name) | ||||
|         return this.__filterAttrs(attrs, type, name); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @@ -167,48 +170,62 @@ class NoteShort { | ||||
|      * @returns {Attribute[]} all note's attributes, including inherited ones | ||||
|      */ | ||||
|     getAttributes(type, name) { | ||||
|         const ownedAttributes = this.getOwnedAttributes(); | ||||
|         return this.__filterAttrs(this.__getCachedAttributes([]), type, name); | ||||
|     } | ||||
| 
 | ||||
|         const attrArrs = [ | ||||
|             ownedAttributes | ||||
|         ]; | ||||
| 
 | ||||
|         for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) { | ||||
|             const templateNote = this.treeCache.getNoteFromCache(templateAttr.value); | ||||
| 
 | ||||
|             if (templateNote) { | ||||
|                 attrArrs.push(templateNote.getAttributes()); | ||||
|             } | ||||
|     __getCachedAttributes(path) { | ||||
|         // notes/clones cannot form tree cycles, it is possible to create attribute inheritance cycle via templates
 | ||||
|         // when template instance is a parent of template itself
 | ||||
|         if (path.includes(this.noteId)) { | ||||
|             return []; | ||||
|         } | ||||
| 
 | ||||
|         if (this.noteId !== 'root') { | ||||
|             for (const parentNote of this.getParentNotes()) { | ||||
|                 // these virtual parent-child relationships are also loaded into frontend tree cache
 | ||||
|                 if (parentNote.type !== 'search') { | ||||
|                     attrArrs.push(parentNote.getInheritableAttributes()); | ||||
|         if (!(this.noteId in noteAttributeCache)) { | ||||
|             const ownedAttributes = this.getOwnedAttributes(); | ||||
| 
 | ||||
|             const attrArrs = [ | ||||
|                 ownedAttributes | ||||
|             ]; | ||||
| 
 | ||||
|             const newPath = [...path, this.noteId]; | ||||
| 
 | ||||
|             for (const templateAttr of ownedAttributes.filter(oa => oa.type === 'relation' && oa.name === 'template')) { | ||||
|                 const templateNote = this.treeCache.notes[templateAttr.value]; | ||||
| 
 | ||||
|                 if (templateNote && templateNote.noteId !== this.noteId) { | ||||
|                     attrArrs.push(templateNote.__getCachedAttributes(newPath)); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (this.noteId !== 'root') { | ||||
|                 for (const parentNote of this.getParentNotes()) { | ||||
|                     // these virtual parent-child relationships are also loaded into frontend tree cache
 | ||||
|                     if (parentNote.type !== 'search') { | ||||
|                         attrArrs.push(parentNote.__getInheritableAttributes(newPath)); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             noteAttributeCache.attributes[this.noteId] = attrArrs.flat(); | ||||
|         } | ||||
| 
 | ||||
|         const attributes = attrArrs.flat(); | ||||
| 
 | ||||
|         return this.__filterAttrs(attributes, type, name); | ||||
|         return noteAttributeCache.attributes[this.noteId]; | ||||
|     } | ||||
| 
 | ||||
|     __filterAttrs(attributes, type, name) { | ||||
|         if (type && name) { | ||||
|         if (!type && !name) { | ||||
|             return attributes; | ||||
|         } else if (type && name) { | ||||
|             return attributes.filter(attr => attr.type === type && attr.name === name); | ||||
|         } else if (type) { | ||||
|             return attributes.filter(attr => attr.type === type); | ||||
|         } else if (name) { | ||||
|             return attributes.filter(attr => attr.name === name); | ||||
|         } else { | ||||
|             return attributes; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     getInheritableAttributes() { | ||||
|         const attrs = this.getAttributes(); | ||||
|     __getInheritableAttributes(path) { | ||||
|         const attrs = this.__getCachedAttributes(path); | ||||
| 
 | ||||
|         return attrs.filter(attr => attr.isInheritable); | ||||
|     } | ||||
| @@ -420,6 +437,35 @@ class NoteShort { | ||||
|         return targets; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @returns {NoteShort[]} | ||||
|      */ | ||||
|     getTemplateNotes() { | ||||
|         const relations = this.getRelations('template'); | ||||
| 
 | ||||
|         return relations.map(rel => this.treeCache.notes[rel.value]); | ||||
|     } | ||||
| 
 | ||||
|     hasAncestor(ancestorNote) { | ||||
|         if (this.noteId === ancestorNote.noteId) { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         for (const templateNote of this.getTemplateNotes()) { | ||||
|             if (templateNote.hasAncestor(ancestorNote)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         for (const parentNote of this.getParentNotes()) { | ||||
|             if (parentNote.hasAncestor(ancestorNote)) {console.log(parentNote); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Clear note's attributes cache to force fresh reload for next attribute request. | ||||
|      * Cache is note instance scoped. | ||||
| @@ -438,6 +484,15 @@ class NoteShort { | ||||
|             .map(attributeId => this.treeCache.attributes[attributeId]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Return note complement which is most importantly note's content | ||||
|      * | ||||
|      * @return {Promise<NoteComplement>} | ||||
|      */ | ||||
|     async getNoteComplement() { | ||||
|         return await this.treeCache.getNoteComplement(this.noteId); | ||||
|     } | ||||
| 
 | ||||
|     get toString() { | ||||
|         return `Note(noteId=${this.noteId}, title=${this.title})`; | ||||
|     } | ||||
| @@ -455,4 +510,4 @@ class NoteShort { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export default NoteShort; | ||||
| export default NoteShort; | ||||
							
								
								
									
										46
									
								
								src/public/app/layouts/desktop_extra_window_layout.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/public/app/layouts/desktop_extra_window_layout.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| import FlexContainer from "../widgets/flex_container.js"; | ||||
| import GlobalMenuWidget from "../widgets/global_menu.js"; | ||||
| import TabRowWidget from "../widgets/tab_row.js"; | ||||
| import TitleBarButtonsWidget from "../widgets/title_bar_buttons.js"; | ||||
| import NoteTreeWidget from "../widgets/note_tree.js"; | ||||
| import TabCachingWidget from "../widgets/tab_caching_widget.js"; | ||||
| import NoteTitleWidget from "../widgets/note_title.js"; | ||||
| import RunScriptButtonsWidget from "../widgets/run_script_buttons.js"; | ||||
| import NoteTypeWidget from "../widgets/note_type.js"; | ||||
| import NoteActionsWidget from "../widgets/note_actions.js"; | ||||
| import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; | ||||
| import NoteDetailWidget from "../widgets/note_detail.js"; | ||||
|  | ||||
| export default class DesktopExtraWindowLayout { | ||||
|     constructor(customWidgets) { | ||||
|         this.customWidgets = customWidgets; | ||||
|     } | ||||
|  | ||||
|     getRootWidget(appContext) { | ||||
|         appContext.mainTreeWidget = new NoteTreeWidget(); | ||||
|  | ||||
|         return new FlexContainer('column') | ||||
|             .setParent(appContext) | ||||
|             .id('root-widget') | ||||
|             .css('height', '100vh') | ||||
|             .child(new FlexContainer('row') | ||||
|                 .child(new GlobalMenuWidget()) | ||||
|                 .child(new TabRowWidget()) | ||||
|                 .child(new TitleBarButtonsWidget())) | ||||
|             .child(new FlexContainer('row') | ||||
|                 .collapsible() | ||||
|                 .child(new FlexContainer('column').id('center-pane').css('flex-grow', '1') | ||||
|                     .child(new FlexContainer('row').class('title-row') | ||||
|                         .cssBlock('.title-row > * { margin: 5px; }') | ||||
|                         .child(new NoteTitleWidget()) | ||||
|                         .child(new RunScriptButtonsWidget().hideInZenMode()) | ||||
|                         .child(new NoteTypeWidget().hideInZenMode()) | ||||
|                         .child(new NoteActionsWidget().hideInZenMode()) | ||||
|                     ) | ||||
|                     .child(new TabCachingWidget(() => new PromotedAttributesWidget())) | ||||
|                     .child(new TabCachingWidget(() => new NoteDetailWidget())) | ||||
|                     .child(...this.customWidgets.get('center-pane')) | ||||
|                 ) | ||||
|             ); | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +1,30 @@ | ||||
| import FlexContainer from "./flex_container.js"; | ||||
| import GlobalMenuWidget from "./global_menu.js"; | ||||
| import TabRowWidget from "./tab_row.js"; | ||||
| import TitleBarButtonsWidget from "./title_bar_buttons.js"; | ||||
| import StandardTopWidget from "./standard_top_widget.js"; | ||||
| import SidePaneContainer from "./side_pane_container.js"; | ||||
| import GlobalButtonsWidget from "./global_buttons.js"; | ||||
| import SearchBoxWidget from "./search_box.js"; | ||||
| import SearchResultsWidget from "./search_results.js"; | ||||
| import NoteTreeWidget from "./note_tree.js"; | ||||
| import TabCachingWidget from "./tab_caching_widget.js"; | ||||
| import NotePathsWidget from "./note_paths.js"; | ||||
| import NoteTitleWidget from "./note_title.js"; | ||||
| import RunScriptButtonsWidget from "./run_script_buttons.js"; | ||||
| import ProtectedNoteSwitchWidget from "./protected_note_switch.js"; | ||||
| import NoteTypeWidget from "./note_type.js"; | ||||
| import NoteActionsWidget from "./note_actions.js"; | ||||
| import PromotedAttributesWidget from "./promoted_attributes.js"; | ||||
| import NoteDetailWidget from "./note_detail.js"; | ||||
| import NoteInfoWidget from "./note_info.js"; | ||||
| import CalendarWidget from "./calendar.js"; | ||||
| import AttributesWidget from "./attributes.js"; | ||||
| import LinkMapWidget from "./link_map.js"; | ||||
| import NoteRevisionsWidget from "./note_revisions.js"; | ||||
| import SimilarNotesWidget from "./similar_notes.js"; | ||||
| import WhatLinksHereWidget from "./what_links_here.js"; | ||||
| import SidePaneToggles from "./side_pane_toggles.js"; | ||||
| import appContext from "../services/app_context.js"; | ||||
| import FlexContainer from "../widgets/flex_container.js"; | ||||
| import GlobalMenuWidget from "../widgets/global_menu.js"; | ||||
| import TabRowWidget from "../widgets/tab_row.js"; | ||||
| import TitleBarButtonsWidget from "../widgets/title_bar_buttons.js"; | ||||
| import StandardTopWidget from "../widgets/standard_top_widget.js"; | ||||
| import SidePaneContainer from "../widgets/side_pane_container.js"; | ||||
| import GlobalButtonsWidget from "../widgets/global_buttons.js"; | ||||
| import SearchBoxWidget from "../widgets/search_box.js"; | ||||
| import SearchResultsWidget from "../widgets/search_results.js"; | ||||
| import NoteTreeWidget from "../widgets/note_tree.js"; | ||||
| import TabCachingWidget from "../widgets/tab_caching_widget.js"; | ||||
| import NotePathsWidget from "../widgets/note_paths.js"; | ||||
| import NoteTitleWidget from "../widgets/note_title.js"; | ||||
| import RunScriptButtonsWidget from "../widgets/run_script_buttons.js"; | ||||
| import NoteTypeWidget from "../widgets/note_type.js"; | ||||
| import NoteActionsWidget from "../widgets/note_actions.js"; | ||||
| import PromotedAttributesWidget from "../widgets/promoted_attributes.js"; | ||||
| import NoteDetailWidget from "../widgets/note_detail.js"; | ||||
| import NoteInfoWidget from "../widgets/collapsible_widgets/note_info.js"; | ||||
| import CalendarWidget from "../widgets/collapsible_widgets/calendar.js"; | ||||
| import AttributesWidget from "../widgets/collapsible_widgets/attributes.js"; | ||||
| import LinkMapWidget from "../widgets/collapsible_widgets/link_map.js"; | ||||
| import NoteRevisionsWidget from "../widgets/collapsible_widgets/note_revisions.js"; | ||||
| 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 EditedNotesWidget from "../widgets/collapsible_widgets/edited_notes.js"; | ||||
| 
 | ||||
| const RIGHT_PANE_CSS = ` | ||||
| <style> | ||||
| @@ -98,13 +97,13 @@ const RIGHT_PANE_CSS = ` | ||||
| } | ||||
| </style>`; | ||||
| 
 | ||||
| export default class DesktopLayout { | ||||
| export default class DesktopMainWindowLayout { | ||||
|     constructor(customWidgets) { | ||||
|         this.customWidgets = customWidgets; | ||||
|     } | ||||
| 
 | ||||
|     getRootWidget(appContext) { | ||||
|         appContext.mainTreeWidget = new NoteTreeWidget(); | ||||
|         appContext.mainTreeWidget = new NoteTreeWidget("main"); | ||||
| 
 | ||||
|         return new FlexContainer('column') | ||||
|             .setParent(appContext) | ||||
| @@ -118,6 +117,7 @@ export default class DesktopLayout { | ||||
|                 .hideInZenMode()) | ||||
|             .child(new FlexContainer('row') | ||||
|                 .collapsible() | ||||
|                 .filling() | ||||
|                 .child(new SidePaneContainer('left') | ||||
|                     .hideInZenMode() | ||||
|                     .child(new GlobalButtonsWidget()) | ||||
| @@ -132,7 +132,6 @@ export default class DesktopLayout { | ||||
|                         .cssBlock('.title-row > * { margin: 5px; }') | ||||
|                         .child(new NoteTitleWidget()) | ||||
|                         .child(new RunScriptButtonsWidget().hideInZenMode()) | ||||
|                         .child(new ProtectedNoteSwitchWidget().hideInZenMode()) | ||||
|                         .child(new NoteTypeWidget().hideInZenMode()) | ||||
|                         .child(new NoteActionsWidget().hideInZenMode()) | ||||
|                     ) | ||||
| @@ -145,6 +144,7 @@ export default class DesktopLayout { | ||||
|                     .hideInZenMode() | ||||
|                     .child(new NoteInfoWidget()) | ||||
|                     .child(new TabCachingWidget(() => new CalendarWidget())) | ||||
|                     .child(new TabCachingWidget(() => new EditedNotesWidget())) | ||||
|                     .child(new TabCachingWidget(() => new AttributesWidget())) | ||||
|                     .child(new TabCachingWidget(() => new LinkMapWidget())) | ||||
|                     .child(new TabCachingWidget(() => new NoteRevisionsWidget())) | ||||
| @@ -155,4 +155,4 @@ export default class DesktopLayout { | ||||
|                 .child(new SidePaneToggles().hideInZenMode()) | ||||
|             ); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,11 +1,11 @@ | ||||
| import FlexContainer from "./flex_container.js"; | ||||
| import NoteTitleWidget from "./note_title.js"; | ||||
| import NoteDetailWidget from "./note_detail.js"; | ||||
| import NoteTreeWidget from "./note_tree.js"; | ||||
| import MobileGlobalButtonsWidget from "./mobile_global_buttons.js"; | ||||
| import CloseDetailButtonWidget from "./close_detail_button.js"; | ||||
| import MobileDetailMenuWidget from "./mobile_detail_menu.js"; | ||||
| import ScreenContainer from "./screen_container.js"; | ||||
| import FlexContainer from "../widgets/flex_container.js"; | ||||
| import NoteTitleWidget from "../widgets/note_title.js"; | ||||
| import NoteDetailWidget from "../widgets/note_detail.js"; | ||||
| import NoteTreeWidget from "../widgets/note_tree.js"; | ||||
| import MobileGlobalButtonsWidget from "../widgets/mobile_widgets/mobile_global_buttons.js"; | ||||
| import CloseDetailButtonWidget from "../widgets/mobile_widgets/close_detail_button.js"; | ||||
| import MobileDetailMenuWidget from "../widgets/mobile_widgets/mobile_detail_menu.js"; | ||||
| import ScreenContainer from "../widgets/mobile_widgets/screen_container.js"; | ||||
| 
 | ||||
| const MOBILE_CSS = ` | ||||
| <style> | ||||
| @@ -73,7 +73,7 @@ export default class MobileLayout { | ||||
|             .child(new ScreenContainer("tree", 'column') | ||||
|                 .class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-5 col-md-4 col-lg-4 col-xl-4") | ||||
|                 .child(new MobileGlobalButtonsWidget()) | ||||
|                 .child(new NoteTreeWidget().cssBlock(FANCYTREE_CSS))) | ||||
|                 .child(new NoteTreeWidget("main").cssBlock(FANCYTREE_CSS))) | ||||
|             .child(new ScreenContainer("detail", "column") | ||||
|                 .class("d-sm-flex d-md-flex d-lg-flex d-xl-flex col-12 col-sm-7 col-md-8 col-lg-8") | ||||
|                 .child(new FlexContainer('row') | ||||
							
								
								
									
										8
									
								
								src/public/app/mobile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/public/app/mobile.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import appContext from "./services/app_context.js"; | ||||
| import MobileLayout from "./layouts/mobile_layout.js"; | ||||
| import glob from "./services/glob.js"; | ||||
|  | ||||
| glob.setupGlobs(); | ||||
|  | ||||
| appContext.setLayout(new MobileLayout()); | ||||
| appContext.start(); | ||||
| @@ -4,15 +4,22 @@ 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"; | ||||
| import keyboardActionsService from "./keyboard_actions.js"; | ||||
| import MobileScreenSwitcherExecutor from "../widgets/mobile_screen_switcher.js"; | ||||
| import MobileScreenSwitcherExecutor from "../widgets/mobile_widgets/mobile_screen_switcher.js"; | ||||
| import MainTreeExecutors from "./main_tree_executors.js"; | ||||
| 
 | ||||
| class AppContext extends Component { | ||||
|     constructor(isMainWindow) { | ||||
|         super(); | ||||
| 
 | ||||
|         this.isMainWindow = isMainWindow; | ||||
|         this.executors = []; | ||||
|     } | ||||
| 
 | ||||
|     setLayout(layout) { | ||||
|         this.layout = layout; | ||||
|     } | ||||
| @@ -20,11 +27,15 @@ class AppContext extends Component { | ||||
|     async start() { | ||||
|         await Promise.all([treeCache.initializedPromise, options.initializedPromise]); | ||||
| 
 | ||||
|         $("#loading-indicator").hide(); | ||||
| 
 | ||||
|         this.showWidgets(); | ||||
| 
 | ||||
|         this.tabManager.loadTabs(); | ||||
| 
 | ||||
|         setTimeout(() => bundleService.executeStartupBundles(), 2000); | ||||
|         if (utils.isDesktop()) { | ||||
|             setTimeout(() => bundleService.executeStartupBundles(), 2000); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     showWidgets() { | ||||
| @@ -35,10 +46,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(); | ||||
| @@ -61,7 +74,7 @@ class AppContext extends Component { | ||||
|         } | ||||
| 
 | ||||
|         if (utils.isElectron()) { | ||||
|             this.child(new ZoomService()); | ||||
|             this.child(zoomService); | ||||
|         } | ||||
| 
 | ||||
|         this.triggerEvent('initialRenderComplete'); | ||||
| @@ -82,6 +95,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); | ||||
| @@ -90,15 +105,9 @@ class AppContext extends Component { | ||||
|     getComponentByEl(el) { | ||||
|         return $(el).closest(".component").prop('component'); | ||||
|     } | ||||
| 
 | ||||
|     async protectedSessionStartedEvent() { | ||||
|         await treeCache.loadInitialTree(); | ||||
| 
 | ||||
|         this.triggerEvent('treeCacheReloaded'); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const appContext = new AppContext(); | ||||
| const appContext = new AppContext(window.glob.isMainWindow); | ||||
| 
 | ||||
| // we should save all outstanding changes before the page/app is closed
 | ||||
| $(window).on('beforeunload', () => { | ||||
| @@ -126,4 +135,4 @@ $(window).on('hashchange', function() { | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| export default appContext; | ||||
| export default appContext; | ||||
| @@ -45,7 +45,7 @@ async function moveAfterBranch(branchIdsToMove, afterBranchId) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function moveToParentNote(branchIdsToMove, newParentNoteId) { | ||||
| async function moveToParentNote(branchIdsToMove, newParentBranchId) { | ||||
|     branchIdsToMove = filterRootNote(branchIdsToMove); | ||||
| 
 | ||||
|     for (const branchIdToMove of branchIdsToMove) { | ||||
| @@ -56,7 +56,7 @@ async function moveToParentNote(branchIdsToMove, newParentNoteId) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         const resp = await server.put(`branches/${branchIdToMove}/move-to/${newParentNoteId}`); | ||||
|         const resp = await server.put(`branches/${branchIdToMove}/move-to/${newParentBranchId}`); | ||||
| 
 | ||||
|         if (!resp.success) { | ||||
|             alert(resp.message); | ||||
| @@ -198,8 +198,8 @@ ws.subscribeToMessages(async message => { | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| async function cloneNoteTo(childNoteId, parentNoteId, prefix) { | ||||
|     const resp = await server.put('notes/' + childNoteId + '/clone-to/' + parentNoteId, { | ||||
| async function cloneNoteTo(childNoteId, parentBranchId, prefix) { | ||||
|     const resp = await server.put(`notes/${childNoteId}/clone-to/${parentBranchId}`, { | ||||
|         prefix: prefix | ||||
|     }); | ||||
| 
 | ||||
| @@ -225,4 +225,4 @@ export default { | ||||
|     moveNodeUpInHierarchy, | ||||
|     cloneNoteAfter, | ||||
|     cloneNoteTo | ||||
| }; | ||||
| }; | ||||
| @@ -1,7 +1,6 @@ | ||||
| import ScriptContext from "./script_context.js"; | ||||
| import server from "./server.js"; | ||||
| import toastService from "./toast.js"; | ||||
| import treeCache from "./tree_cache.js"; | ||||
| 
 | ||||
| async function getAndExecuteBundle(noteId, originEntity = null) { | ||||
|     const bundle = await server.get('script/bundle/' + noteId); | ||||
| @@ -77,4 +76,4 @@ export default { | ||||
|     getAndExecuteBundle, | ||||
|     executeStartupBundles, | ||||
|     getWidgetBundlesByParent | ||||
| } | ||||
| } | ||||
| @@ -33,13 +33,13 @@ async function pasteAfter(afterBranchId) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function pasteInto(parentNoteId) { | ||||
| async function pasteInto(parentBranchId) { | ||||
|     if (isClipboardEmpty()) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     if (clipboardMode === 'cut') { | ||||
|         await branchService.moveToParentNote(clipboardBranchIds, parentNoteId); | ||||
|         await branchService.moveToParentNote(clipboardBranchIds, parentBranchId); | ||||
| 
 | ||||
|         clipboardBranchIds = []; | ||||
|         clipboardMode = null; | ||||
| @@ -50,7 +50,7 @@ async function pasteInto(parentNoteId) { | ||||
|         for (const clipboardBranch of clipboardBranches) { | ||||
|             const clipboardNote = await clipboardBranch.getNote(); | ||||
| 
 | ||||
|             await branchService.cloneNoteTo(clipboardNote.noteId, parentNoteId); | ||||
|             await branchService.cloneNoteTo(clipboardNote.noteId, parentBranchId); | ||||
|         } | ||||
| 
 | ||||
|         // copy will keep clipboardBranchIds and clipboardMode so it's possible to paste into multiple places
 | ||||
| @@ -89,4 +89,4 @@ export default { | ||||
|     cut, | ||||
|     copy, | ||||
|     isClipboardEmpty | ||||
| } | ||||
| } | ||||
| @@ -1,14 +1,13 @@ | ||||
| import utils from "./utils.js"; | ||||
| import treeService from "./tree.js"; | ||||
| import dateNoteService from "./date_notes.js"; | ||||
| import hoistedNoteService from "./hoisted_note.js"; | ||||
| import treeCache from "./tree_cache.js"; | ||||
| import server from "./server.js"; | ||||
| import appContext from "./app_context.js"; | ||||
| 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() { | ||||
| @@ -36,7 +35,7 @@ export default class Entrypoints extends Component { | ||||
| 
 | ||||
|     openDevToolsCommand() { | ||||
|         if (utils.isElectron()) { | ||||
|             require('electron').remote.getCurrentWindow().toggleDevTools(); | ||||
|             utils.dynamicRequire('electron').remote.getCurrentWindow().toggleDevTools(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @@ -45,8 +44,8 @@ export default class Entrypoints extends Component { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const {remote} = require('electron'); | ||||
|         const {FindInPage} = require('electron-find'); | ||||
|         const {remote} = utils.dynamicRequire('electron'); | ||||
|         const {FindInPage} = utils.dynamicRequire('electron-find'); | ||||
|         const findInPage = new FindInPage(remote.getCurrentWebContents(), { | ||||
|             offsetTop: 10, | ||||
|             offsetRight: 10, | ||||
| @@ -98,7 +97,7 @@ export default class Entrypoints extends Component { | ||||
| 
 | ||||
|     toggleFullscreenCommand() { | ||||
|         if (utils.isElectron()) { | ||||
|             const win = require('electron').remote.getCurrentWindow(); | ||||
|             const win = utils.dynamicRequire('electron').remote.getCurrentWindow(); | ||||
| 
 | ||||
|             if (win.isFullScreenable()) { | ||||
|                 win.setFullScreen(!win.isFullScreen()); | ||||
| @@ -139,7 +138,7 @@ export default class Entrypoints extends Component { | ||||
|     backInNoteHistoryCommand() { | ||||
|         if (utils.isElectron()) { | ||||
|             // standard JS version does not work completely correctly in electron
 | ||||
|             const webContents = require('electron').remote.getCurrentWebContents(); | ||||
|             const webContents = utils.dynamicRequire('electron').remote.getCurrentWebContents(); | ||||
|             const activeIndex = parseInt(webContents.getActiveIndex()); | ||||
| 
 | ||||
|             webContents.goToIndex(activeIndex - 1); | ||||
| @@ -152,7 +151,7 @@ export default class Entrypoints extends Component { | ||||
|     forwardInNoteHistoryCommand() { | ||||
|         if (utils.isElectron()) { | ||||
|             // standard JS version does not work completely correctly in electron
 | ||||
|             const webContents = require('electron').remote.getCurrentWebContents(); | ||||
|             const webContents = utils.dynamicRequire('electron').remote.getCurrentWebContents(); | ||||
|             const activeIndex = parseInt(webContents.getActiveIndex()); | ||||
| 
 | ||||
|             webContents.goToIndex(activeIndex + 1); | ||||
| @@ -184,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"); | ||||
|     } | ||||
| } | ||||
| @@ -403,6 +403,13 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | ||||
|      * @method | ||||
|      */ | ||||
|     this.waitUntilSynced = ws.waitForMaxKnownSyncId; | ||||
| 
 | ||||
|     /** | ||||
|      * This will refresh all currently opened notes which have included note specified in the parameter | ||||
|      * | ||||
|      * @param includedNoteId - noteId of the included note | ||||
|      */ | ||||
|     this.refreshIncludedNote = includedNoteId => appContext.triggerEvent('refreshIncludedNote', {noteId: includedNoteId}); | ||||
| } | ||||
| 
 | ||||
| export default FrontendScriptApi; | ||||
| export default FrontendScriptApi; | ||||
							
								
								
									
										91
									
								
								src/public/app/services/glob.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/public/app/services/glob.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| import utils from "./utils.js"; | ||||
| import appContext from "./app_context.js"; | ||||
| import server from "./server.js"; | ||||
| import libraryLoader from "./library_loader.js"; | ||||
| import ws from "./ws.js"; | ||||
| import protectedSessionHolder from "./protected_session_holder.js"; | ||||
| import treeCache from "./tree_cache.js"; | ||||
|  | ||||
| function setupGlobs() { | ||||
|     window.glob.PROFILING_LOG = false; | ||||
|  | ||||
|     window.glob.isDesktop = utils.isDesktop; | ||||
|     window.glob.isMobile = utils.isMobile; | ||||
|  | ||||
|     window.glob.getComponentByEl = el => appContext.getComponentByEl(el); | ||||
|     window.glob.getHeaders = server.getHeaders; | ||||
|  | ||||
|     // required for ESLint plugin and CKEditor | ||||
|     window.glob.getActiveTabNote = () => appContext.tabManager.getActiveTabNote(); | ||||
|     window.glob.requireLibrary = libraryLoader.requireLibrary; | ||||
|     window.glob.ESLINT = libraryLoader.ESLINT; | ||||
|     window.glob.appContext = appContext; // for debugging | ||||
|     window.glob.treeCache = treeCache; | ||||
|  | ||||
|     // for CKEditor integration (button on block toolbar) | ||||
|     window.glob.importMarkdownInline = async () => { | ||||
|         const dialog = await import("../dialogs/markdown_import.js"); | ||||
|  | ||||
|         dialog.importMarkdownInline(); | ||||
|     }; | ||||
|  | ||||
|     window.glob.SEARCH_HELP_TEXT = ` | ||||
|     <strong>Search tips</strong> - also see <button class="btn btn-sm" type="button" data-help-page="Search">complete help on search</button> | ||||
|     <p> | ||||
|     <ul> | ||||
|         <li>Just enter any text for full text search</li> | ||||
|         <li><code>@abc</code> - returns notes with label abc</li> | ||||
|         <li><code>@year=2019</code> - matches notes with label <code>year</code> having value <code>2019</code></li> | ||||
|         <li><code>@rock @pop</code> - matches notes which have both <code>rock</code> and <code>pop</code> labels</li> | ||||
|         <li><code>@rock or @pop</code> - only one of the labels must be present</li> | ||||
|         <li><code>@year<=2000</code> - numerical comparison (also >, >=, <).</li> | ||||
|         <li><code>@dateCreated>=MONTH-1</code> - notes created in the last month</li> | ||||
|         <li><code>=handler</code> - will execute script defined in <code>handler</code> relation to get results</li> | ||||
|     </ul> | ||||
|     </p>`; | ||||
|  | ||||
|     window.onerror = function (msg, url, lineNo, columnNo, error) { | ||||
|         const string = msg.toLowerCase(); | ||||
|  | ||||
|         let message = "Uncaught error: "; | ||||
|  | ||||
|         if (string.includes("script error")) { | ||||
|             message += 'No details available'; | ||||
|         } else { | ||||
|             message += [ | ||||
|                 'Message: ' + msg, | ||||
|                 'URL: ' + url, | ||||
|                 'Line: ' + lineNo, | ||||
|                 'Column: ' + columnNo, | ||||
|                 'Error object: ' + JSON.stringify(error), | ||||
|                 'Stack: ' + error && error.stack | ||||
|             ].join(', '); | ||||
|         } | ||||
|  | ||||
|         ws.logError(message); | ||||
|  | ||||
|         return false; | ||||
|     }; | ||||
|  | ||||
|     protectedSessionHolder.setProtectedSessionId(null); | ||||
|  | ||||
|     for (const appCssNoteId of glob.appCssNoteIds || []) { | ||||
|         libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`); | ||||
|     } | ||||
|  | ||||
|     const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/"; | ||||
|  | ||||
|     $(document).on("click", "button[data-help-page]", e => { | ||||
|         const $button = $(e.target); | ||||
|  | ||||
|         window.open(wikiBaseUrl + $button.attr("data-help-page"), '_blank'); | ||||
|     }); | ||||
|  | ||||
|     $("body").on("click", "a.external", function () { | ||||
|         window.open($(this).attr("href"), '_blank'); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     setupGlobs | ||||
| } | ||||
| @@ -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,12 +118,16 @@ 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 tab", command: "openNoteInNewTab", uiIcon: "empty"}, | ||||
|             {title: "Open note in new window", command: "openNoteInNewWindow", uiIcon: "window-open"} | ||||
|         ], | ||||
|         selectMenuItemHandler: ({command}) => { | ||||
|             if (command === 'openNoteInNewTab') { | ||||
|                 appContext.tabManager.openTabWithNote(notePath); | ||||
|             } | ||||
|             else if (command === 'openNoteInNewWindow') { | ||||
|                 appContext.openInNewWindow(notePath); | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| @@ -128,7 +137,7 @@ function newTabContextMenu(e) { | ||||
| $(document).on('mousedown', "a[data-action='note']", goToLink); | ||||
| $(document).on('mousedown', 'div.popover-content a, div.ui-tooltip-content a', goToLink); | ||||
| $(document).on('dblclick', '.note-detail-text a', goToLink); | ||||
| $(document).on('mousedown', '.note-detail-text a', function (e) { | ||||
| $(document).on('mousedown', '.note-detail-text a:not(.reference-link)', function (e) { | ||||
|     const $link = $(e.target).closest("a"); | ||||
|     const notePath = getNotePathFromLink($link); | ||||
| 
 | ||||
| @@ -151,20 +160,26 @@ $(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.reference-link', goToLink); | ||||
| $(document).on('mousedown', '.note-detail-readonly-text a', goToLink); | ||||
| $(document).on('mousedown', 'a.ck-link-actions__preview', goToLink); | ||||
| $(document).on('click', 'section.include-note a', 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', '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); | ||||
| $(document).on('contextmenu', "section.include-note a", linkContextMenu); | ||||
| 
 | ||||
| export default { | ||||
|     getNotePathFromUrl, | ||||
|     createNoteLink, | ||||
|     goToLink | ||||
| }; | ||||
| }; | ||||
| @@ -4,7 +4,7 @@ export default class LoadResults { | ||||
| 
 | ||||
|         this.noteIdToSourceId = {}; | ||||
|         this.sourceIdToNoteIds = {}; | ||||
|          | ||||
| 
 | ||||
|         this.branches = []; | ||||
| 
 | ||||
|         this.attributes = []; | ||||
| @@ -54,8 +54,9 @@ export default class LoadResults { | ||||
|         this.attributes.push({attributeId, sourceId}); | ||||
|     } | ||||
| 
 | ||||
|     getAttributes() { | ||||
|     getAttributes(sourceId = 'none') { | ||||
|         return this.attributes | ||||
|             .filter(row => row.sourceId !== sourceId) | ||||
|             .map(row => this.treeCache.attributes[row.attributeId]) | ||||
|             .filter(attr => !!attr); | ||||
|     } | ||||
| @@ -101,6 +102,15 @@ export default class LoadResults { | ||||
|         this.options.includes(name); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @return {boolean} true if there are changes which could affect the attributes (including inherited ones) | ||||
|      *          notably changes in note itself should not have any effect on attributes | ||||
|      */ | ||||
|     hasAttributeRelatedChanges() { | ||||
|         return this.branches.length === 0 | ||||
|             && this.attributes.length === 0; | ||||
|     } | ||||
| 
 | ||||
|     isEmpty() { | ||||
|         return Object.keys(this.noteIdToSourceId).length === 0 | ||||
|             && this.branches.length === 0 | ||||
| @@ -110,4 +120,4 @@ export default class LoadResults { | ||||
|             && this.contentNoteIdToSourceId.length === 0 | ||||
|             && this.options.length === 0; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -34,14 +34,10 @@ export default class MainTreeExecutors extends Component { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const {note} = await noteCreateService.createNote(activeNote.noteId, { | ||||
|         await noteCreateService.createNote(activeNote.noteId, { | ||||
|             isProtected: activeNote.isProtected, | ||||
|             saveSelection: false | ||||
|         }); | ||||
| 
 | ||||
|         await ws.waitForMaxKnownSyncId(); | ||||
| 
 | ||||
|         appContext.tabManager.getActiveTabContext().setNote(note.noteId); | ||||
|     } | ||||
| 
 | ||||
|     async createNoteAfterCommand() { | ||||
| @@ -53,15 +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); | ||||
|     } | ||||
| } | ||||
| } | ||||
							
								
								
									
										20
									
								
								src/public/app/services/note_attribute_cache.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/public/app/services/note_attribute_cache.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| /** | ||||
|  * Purpose of this class is to cache list of attributes for notes. | ||||
|  * | ||||
|  * Cache invalidation granularity is global - whenever a write operation is detected to notes, branches or attributes | ||||
|  * we invalidate the whole cache. That's OK, since the purpose for this is to speed up batch read-only operations, such | ||||
|  * as loading the tree which uses attributes heavily. | ||||
|  */ | ||||
| class NoteAttributeCache { | ||||
|     constructor() { | ||||
|         this.attributes = {}; | ||||
|     } | ||||
|  | ||||
|     invalidate() { | ||||
|         this.attributes = {}; | ||||
|     } | ||||
| } | ||||
|  | ||||
| const noteAttributeCache = new NoteAttributeCache(); | ||||
|  | ||||
| export default noteAttributeCache; | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user