mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	Compare commits
	
		
			324 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a44f43b133 | ||
| 
						 | 
					69677b15fe | ||
| 
						 | 
					cdb17ae937 | ||
| 
						 | 
					c240fb9896 | ||
| 
						 | 
					4b41eddf44 | ||
| 
						 | 
					b51ac112a2 | ||
| 
						 | 
					c2e3a3fe04 | ||
| 
						 | 
					b2052a6ccd | ||
| 
						 | 
					a07479cd5a | ||
| 
						 | 
					3820384f51 | ||
| 
						 | 
					0610576e5a | ||
| 
						 | 
					efac7701eb | ||
| 
						 | 
					27cee1cf33 | ||
| 
						 | 
					b4c6d9f800 | ||
| 
						 | 
					24c8b39d8e | ||
| 
						 | 
					0144dc12df | ||
| 
						 | 
					65684550a8 | ||
| 
						 | 
					6d09931a39 | ||
| 
						 | 
					37d2a7939c | ||
| 
						 | 
					a432ad7483 | ||
| 
						 | 
					ae17e4dc60 | ||
| 
						 | 
					02eddc347a | ||
| 
						 | 
					ee58bf3d5c | ||
| 
						 | 
					ecbaffa5f3 | ||
| 
						 | 
					fe86c09f22 | ||
| 
						 | 
					c8e01d6cce | ||
| 
						 | 
					7c404f03db | ||
| 
						 | 
					ed1cf6aad5 | ||
| 
						 | 
					9703fd61e2 | ||
| 
						 | 
					16790e388b | ||
| 
						 | 
					b48474998b | ||
| 
						 | 
					95d8f07458 | ||
| 
						 | 
					e628c30c89 | ||
| 
						 | 
					52a8aae74f | ||
| 
						 | 
					54b5898582 | ||
| 
						 | 
					64974d75d5 | ||
| 
						 | 
					bd118027fb | ||
| 
						 | 
					36de217835 | ||
| 
						 | 
					b5283d58bb | ||
| 
						 | 
					8414d97ffa | ||
| 
						 | 
					9f30d4e673 | ||
| 
						 | 
					8e0d1fa0df | ||
| 
						 | 
					5b251b9977 | ||
| 
						 | 
					8b3e721028 | ||
| 
						 | 
					7e2a2baa5d | ||
| 
						 | 
					003eed368b | ||
| 
						 | 
					4b1cf05c0e | ||
| 
						 | 
					d9429c4f4b | ||
| 
						 | 
					b7bd94b6b0 | ||
| 
						 | 
					51bbc10744 | ||
| 
						 | 
					fb5df33ee7 | ||
| 
						 | 
					d8ba0ccd7d | ||
| 
						 | 
					886ea6c68c | ||
| 
						 | 
					936f85c09e | ||
| 
						 | 
					b25deea21d | ||
| 
						 | 
					cf5ec44303 | ||
| 
						 | 
					6f956c2415 | ||
| 
						 | 
					3533160bef | ||
| 
						 | 
					60cbfdcabd | ||
| 
						 | 
					604f036a54 | ||
| 
						 | 
					dd4f3ec264 | ||
| 
						 | 
					ff67b8a0ba | ||
| 
						 | 
					1d5fb0b646 | ||
| 
						 | 
					80931a318f | ||
| 
						 | 
					16f16cb36a | ||
| 
						 | 
					899f24cde5 | ||
| 
						 | 
					9f29521ab8 | ||
| 
						 | 
					c1ce0c6b22 | ||
| 
						 | 
					a7fce33750 | ||
| 
						 | 
					6fd8e73150 | ||
| 
						 | 
					1359dd86c2 | ||
| 
						 | 
					a1b610fc50 | ||
| 
						 | 
					c849d719e9 | ||
| 
						 | 
					96de2e7008 | ||
| 
						 | 
					f140b77e7c | ||
| 
						 | 
					22228de63b | ||
| 
						 | 
					b0596c9eb2 | ||
| 
						 | 
					2a2319d434 | ||
| 
						 | 
					dad47d115f | ||
| 
						 | 
					502026359c | ||
| 
						 | 
					47b0e4e4d3 | ||
| 
						 | 
					6c927d9159 | ||
| 
						 | 
					ddc79b2517 | ||
| 
						 | 
					4c2e12d2cb | ||
| 
						 | 
					14f7a8b7b9 | ||
| 
						 | 
					caa7dd9619 | ||
| 
						 | 
					8aa7e2d0a0 | ||
| 
						 | 
					6be8a3f343 | ||
| 
						 | 
					a097cefba7 | ||
| 
						 | 
					e4c78f3887 | ||
| 
						 | 
					5baa251944 | ||
| 
						 | 
					cde68abec9 | ||
| 
						 | 
					51175e3676 | ||
| 
						 | 
					45ddfef30a | ||
| 
						 | 
					1e1d78999e | ||
| 
						 | 
					92fcd7b345 | ||
| 
						 | 
					e04f1cd574 | ||
| 
						 | 
					176c3a5d51 | ||
| 
						 | 
					c09570cf39 | ||
| 
						 | 
					4a093000be | ||
| 
						 | 
					6952b643ae | ||
| 
						 | 
					c487a95bc7 | ||
| 
						 | 
					8884177d9f | ||
| 
						 | 
					8b250ed523 | ||
| 
						 | 
					d8b78d8025 | ||
| 
						 | 
					42112b8053 | ||
| 
						 | 
					6cc0dd5a80 | ||
| 
						 | 
					afd5f4823f | ||
| 
						 | 
					b0cf82c91b | ||
| 
						 | 
					6a67cdd5af | ||
| 
						 | 
					bad7b84993 | ||
| 
						 | 
					d3ca6b5ae6 | ||
| 
						 | 
					da5009f089 | ||
| 
						 | 
					c08524c977 | ||
| 
						 | 
					f89537037e | ||
| 
						 | 
					c153793766 | ||
| 
						 | 
					0aec5927d5 | ||
| 
						 | 
					8aea9a1801 | ||
| 
						 | 
					73247e3220 | ||
| 
						 | 
					89344a6eda | ||
| 
						 | 
					40d2e6ea83 | ||
| 
						 | 
					910cfe9a17 | ||
| 
						 | 
					e58a80fc00 | ||
| 
						 | 
					4a2319cb33 | ||
| 
						 | 
					5619088c41 | ||
| 
						 | 
					60271993eb | ||
| 
						 | 
					6695e8b011 | ||
| 
						 | 
					707df18b93 | ||
| 
						 | 
					90895f1288 | ||
| 
						 | 
					ba1ca506af | ||
| 
						 | 
					f90ed99a40 | ||
| 
						 | 
					67630b1a22 | ||
| 
						 | 
					2c1580ea65 | ||
| 
						 | 
					840a0b5f64 | ||
| 
						 | 
					b39f6ef7ad | ||
| 
						 | 
					fb27088fcd | ||
| 
						 | 
					76fbff68ba | ||
| 
						 | 
					54de4d236d | ||
| 
						 | 
					e211dd65ad | ||
| 
						 | 
					a87f4d8653 | ||
| 
						 | 
					b59c175c2e | ||
| 
						 | 
					580104c4c5 | ||
| 
						 | 
					0fc3053b0a | ||
| 
						 | 
					929e0f69c2 | ||
| 
						 | 
					e70af1300a | ||
| 
						 | 
					4d0e46021b | ||
| 
						 | 
					1a9a49b739 | ||
| 
						 | 
					2ac560c56e | ||
| 
						 | 
					c23387c0fb | ||
| 
						 | 
					0ff250fe15 | ||
| 
						 | 
					52b1e58b26 | ||
| 
						 | 
					484715e440 | ||
| 
						 | 
					9d42c3d802 | ||
| 
						 | 
					c654172d33 | ||
| 
						 | 
					e17b26c883 | ||
| 
						 | 
					24d02d9cf5 | ||
| 
						 | 
					7208a311ac | ||
| 
						 | 
					ad7355372b | ||
| 
						 | 
					f18b5babad | ||
| 
						 | 
					9831ec0ca9 | ||
| 
						 | 
					596544eca3 | ||
| 
						 | 
					1f853024ee | ||
| 
						 | 
					0308b13460 | ||
| 
						 | 
					06b8a82f70 | ||
| 
						 | 
					91ca07929d | ||
| 
						 | 
					afabaa5fdb | ||
| 
						 | 
					a6fd3fa77c | ||
| 
						 | 
					58a2c08dcd | ||
| 
						 | 
					299bbff2f4 | ||
| 
						 | 
					19d8947123 | ||
| 
						 | 
					35edce7523 | ||
| 
						 | 
					bc4cec69a5 | ||
| 
						 | 
					cce8c1b674 | ||
| 
						 | 
					aa58788769 | ||
| 
						 | 
					6c62ab7a52 | ||
| 
						 | 
					d6ab638b30 | ||
| 
						 | 
					bd4db406de | ||
| 
						 | 
					e50f9cd0a3 | ||
| 
						 | 
					2b64cbce2c | ||
| 
						 | 
					2797c942ab | ||
| 
						 | 
					f1c3278874 | ||
| 
						 | 
					424c22dcde | ||
| 
						 | 
					5c223dfd12 | ||
| 
						 | 
					6a3e7a5a8e | ||
| 
						 | 
					f88cdac000 | ||
| 
						 | 
					eeead90f32 | ||
| 
						 | 
					b607857409 | ||
| 
						 | 
					9268f88bc3 | ||
| 
						 | 
					f7f0560a9f | ||
| 
						 | 
					3d8905207e | ||
| 
						 | 
					dbc312010b | ||
| 
						 | 
					b115a7cf19 | ||
| 
						 | 
					348562352c | ||
| 
						 | 
					70fd917e7c | ||
| 
						 | 
					d2b60764cd | ||
| 
						 | 
					581b1fdaa5 | ||
| 
						 | 
					3c19a712c0 | ||
| 
						 | 
					cc27f16088 | ||
| 
						 | 
					dffdb82288 | ||
| 
						 | 
					2b32addade | ||
| 
						 | 
					0b251530fa | ||
| 
						 | 
					f5b933149a | ||
| 
						 | 
					48bbfb8bdb | ||
| 
						 | 
					889971c4d6 | ||
| 
						 | 
					0722494d41 | ||
| 
						 | 
					4b977a3306 | ||
| 
						 | 
					3ff3021acd | ||
| 
						 | 
					99e56a9c42 | ||
| 
						 | 
					77279dfe16 | ||
| 
						 | 
					93f8050454 | ||
| 
						 | 
					31cfede7a7 | ||
| 
						 | 
					c8ec86e537 | ||
| 
						 | 
					05aee884b6 | ||
| 
						 | 
					012ba9e060 | ||
| 
						 | 
					8e8fd88857 | ||
| 
						 | 
					523ccdad6b | ||
| 
						 | 
					ded3f605be | ||
| 
						 | 
					62b44e3549 | ||
| 
						 | 
					030d12a465 | ||
| 
						 | 
					4d15628840 | ||
| 
						 | 
					81b849898c | ||
| 
						 | 
					3824486b85 | ||
| 
						 | 
					081ab00a0a | ||
| 
						 | 
					04f6af5c9a | ||
| 
						 | 
					4dc1f1f6eb | ||
| 
						 | 
					3930a02123 | ||
| 
						 | 
					3112de105e | ||
| 
						 | 
					3b8d7b8fba | ||
| 
						 | 
					9fca7f09a5 | ||
| 
						 | 
					fd39d6b3a9 | ||
| 
						 | 
					a103886ea5 | ||
| 
						 | 
					373408e401 | ||
| 
						 | 
					db44c1d8e6 | ||
| 
						 | 
					95a34c9e2d | ||
| 
						 | 
					6ce401f260 | ||
| 
						 | 
					5d74dcd256 | ||
| 
						 | 
					5a9fc1697b | ||
| 
						 | 
					927415838c | ||
| 
						 | 
					d72fcefdc7 | ||
| 
						 | 
					0be173a8f7 | ||
| 
						 | 
					c3913a8735 | ||
| 
						 | 
					e2dfe1b6de | ||
| 
						 | 
					fec3e47eb8 | ||
| 
						 | 
					d72efd2450 | ||
| 
						 | 
					ef1c840aa7 | ||
| 
						 | 
					1581464d8c | ||
| 
						 | 
					9de29584a4 | ||
| 
						 | 
					9e2e6fb50c | ||
| 
						 | 
					c85979b66b | ||
| 
						 | 
					ecdc5865a6 | ||
| 
						 | 
					1771ddb787 | ||
| 
						 | 
					3ab657fe46 | ||
| 
						 | 
					8785dae753 | ||
| 
						 | 
					2f1c5b29d4 | ||
| 
						 | 
					7135349a10 | ||
| 
						 | 
					66c639d5e3 | ||
| 
						 | 
					6704b755d8 | ||
| 
						 | 
					cf96baad48 | ||
| 
						 | 
					32220476aa | ||
| 
						 | 
					86bc84a2ad | ||
| 
						 | 
					de9e0c7929 | ||
| 
						 | 
					6963e662ef | ||
| 
						 | 
					7127822e8f | ||
| 
						 | 
					0a35abf68f | ||
| 
						 | 
					3f8e8f8561 | ||
| 
						 | 
					e02eca87b0 | ||
| 
						 | 
					2f680c4326 | ||
| 
						 | 
					0b4a44a403 | ||
| 
						 | 
					89299f865c | ||
| 
						 | 
					f6db9a50ab | ||
| 
						 | 
					78d9fac1e6 | ||
| 
						 | 
					458ed1faff | ||
| 
						 | 
					0657815de5 | ||
| 
						 | 
					a608832681 | ||
| 
						 | 
					d2f72529b3 | ||
| 
						 | 
					28185af158 | ||
| 
						 | 
					7aacd01ad7 | ||
| 
						 | 
					74cc34696e | ||
| 
						 | 
					d4baac0bb5 | ||
| 
						 | 
					35bc1421f1 | ||
| 
						 | 
					d4db265fd9 | ||
| 
						 | 
					1dad919de9 | ||
| 
						 | 
					246dfbdcb4 | ||
| 
						 | 
					f8d32d64f5 | ||
| 
						 | 
					5dea271d6f | ||
| 
						 | 
					eeb62a6cf2 | ||
| 
						 | 
					35cf8026b0 | ||
| 
						 | 
					e0028ab6f1 | ||
| 
						 | 
					a32645cdeb | ||
| 
						 | 
					812f9f6fca | ||
| 
						 | 
					f7a670ec24 | ||
| 
						 | 
					d0d24f0f4a | ||
| 
						 | 
					042f9b7f2d | ||
| 
						 | 
					2d260cdbed | ||
| 
						 | 
					6a786cad83 | ||
| 
						 | 
					67019b3d6c | ||
| 
						 | 
					1db6e59077 | ||
| 
						 | 
					5e4770875e | ||
| 
						 | 
					e9a77f3f16 | ||
| 
						 | 
					cbec85f295 | ||
| 
						 | 
					14bd5d301d | ||
| 
						 | 
					321d0e8d64 | ||
| 
						 | 
					84e1512031 | ||
| 
						 | 
					b036852b2d | ||
| 
						 | 
					f693dc31e8 | ||
| 
						 | 
					af8f5b11b8 | ||
| 
						 | 
					8ca943f87b | ||
| 
						 | 
					35cc9da626 | ||
| 
						 | 
					44cc86a1a5 | ||
| 
						 | 
					7c3bbfd45e | ||
| 
						 | 
					a1f939e3a0 | ||
| 
						 | 
					4ca7886090 | ||
| 
						 | 
					b942163748 | ||
| 
						 | 
					5b6d15acb3 | ||
| 
						 | 
					841420360e | ||
| 
						 | 
					a680bb4612 | ||
| 
						 | 
					f763e13996 | ||
| 
						 | 
					e73e1262ae | ||
| 
						 | 
					b774d56cf7 | ||
| 
						 | 
					6c16cdb011 | ||
| 
						 | 
					86fcbb0354 | ||
| 
						 | 
					17d030e800 | ||
| 
						 | 
					6fbf28b30d | ||
| 
						 | 
					8171b68b18 | 
							
								
								
									
										7
									
								
								.gitpod.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.gitpod.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
tasks:
 | 
			
		||||
    - before: nvm install 10 && nvm use 10
 | 
			
		||||
      init: npm install
 | 
			
		||||
      command: npm run start
 | 
			
		||||
ports:
 | 
			
		||||
    - port: 8080
 | 
			
		||||
      onOpen: open-preview
 | 
			
		||||
@@ -16,586 +16,662 @@
 | 
			
		||||
    <table id="8" parent="2" name="branches"/>
 | 
			
		||||
    <table id="9" parent="2" name="event_log"/>
 | 
			
		||||
    <table id="10" parent="2" name="links"/>
 | 
			
		||||
    <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">
 | 
			
		||||
    <table id="11" parent="2" name="note_contents"/>
 | 
			
		||||
    <table id="12" parent="2" name="note_revisions"/>
 | 
			
		||||
    <table id="13" parent="2" name="notes"/>
 | 
			
		||||
    <table id="14" parent="2" name="options"/>
 | 
			
		||||
    <table id="15" parent="2" name="recent_notes"/>
 | 
			
		||||
    <table id="16" parent="2" name="source_ids"/>
 | 
			
		||||
    <table id="17" parent="2" name="sqlite_master">
 | 
			
		||||
      <System>1</System>
 | 
			
		||||
    </table>
 | 
			
		||||
    <table id="17" parent="2" name="sqlite_sequence">
 | 
			
		||||
    <table id="18" parent="2" name="sqlite_sequence">
 | 
			
		||||
      <System>1</System>
 | 
			
		||||
    </table>
 | 
			
		||||
    <table id="18" parent="2" name="sync"/>
 | 
			
		||||
    <column id="19" parent="6" name="apiTokenId">
 | 
			
		||||
    <table id="19" parent="2" name="sync"/>
 | 
			
		||||
    <column id="20" parent="6" name="apiTokenId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="20" parent="6" name="token">
 | 
			
		||||
    <column id="21" parent="6" name="token">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="21" parent="6" name="dateCreated">
 | 
			
		||||
    <column id="22" parent="6" name="dateCreated">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="22" parent="6" name="isDeleted">
 | 
			
		||||
    <column id="23" 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">
 | 
			
		||||
    <column id="24" 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">
 | 
			
		||||
    <index id="25" parent="6" name="sqlite_autoindex_api_tokens_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>apiTokenId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="25" parent="6">
 | 
			
		||||
    <key id="26" parent="6">
 | 
			
		||||
      <ColNames>apiTokenId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_api_tokens_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="26" parent="7" name="attributeId">
 | 
			
		||||
    <column id="27" parent="7" name="attributeId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="27" parent="7" name="noteId">
 | 
			
		||||
    <column id="28" parent="7" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="28" parent="7" name="type">
 | 
			
		||||
    <column id="29" parent="7" name="type">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="29" parent="7" name="name">
 | 
			
		||||
    <column id="30" parent="7" name="name">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="30" parent="7" name="value">
 | 
			
		||||
    <column id="31" parent="7" name="value">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>''</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="31" parent="7" name="position">
 | 
			
		||||
    <column id="32" parent="7" name="position">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="32" parent="7" name="dateCreated">
 | 
			
		||||
    <column id="33" parent="7" name="dateCreated">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="33" parent="7" name="dateModified">
 | 
			
		||||
    <column id="34" parent="7" name="dateModified">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="34" parent="7" name="isDeleted">
 | 
			
		||||
    <column id="35" parent="7" name="isDeleted">
 | 
			
		||||
      <Position>9</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="35" parent="7" name="hash">
 | 
			
		||||
    <column id="36" parent="7" name="hash">
 | 
			
		||||
      <Position>10</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="36" parent="7" name="isInheritable">
 | 
			
		||||
    <column id="37" parent="7" name="isInheritable">
 | 
			
		||||
      <Position>11</Position>
 | 
			
		||||
      <DataType>int|0s</DataType>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="37" parent="7" name="sqlite_autoindex_attributes_1">
 | 
			
		||||
    <index id="38" parent="7" name="sqlite_autoindex_attributes_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>attributeId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="38" parent="7">
 | 
			
		||||
    <index id="39" parent="7" name="IDX_attributes_noteId_index">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="40" parent="7" name="IDX_attributes_name_value">
 | 
			
		||||
      <ColNames>name
 | 
			
		||||
value</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="41" parent="7" name="IDX_attributes_name_index">
 | 
			
		||||
      <ColNames>name</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="42" parent="7" name="IDX_attributes_value_index">
 | 
			
		||||
      <ColNames>value</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="43" parent="7">
 | 
			
		||||
      <ColNames>attributeId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_attributes_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="39" parent="8" name="branchId">
 | 
			
		||||
    <column id="44" parent="8" name="branchId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="40" parent="8" name="noteId">
 | 
			
		||||
    <column id="45" parent="8" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="41" parent="8" name="parentNoteId">
 | 
			
		||||
    <column id="46" parent="8" name="parentNoteId">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="42" parent="8" name="notePosition">
 | 
			
		||||
    <column id="47" parent="8" name="notePosition">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="43" parent="8" name="prefix">
 | 
			
		||||
    <column id="48" parent="8" name="prefix">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="44" parent="8" name="isExpanded">
 | 
			
		||||
    <column id="49" parent="8" name="isExpanded">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>BOOLEAN|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="45" parent="8" name="isDeleted">
 | 
			
		||||
    <column id="50" parent="8" name="isDeleted">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="46" parent="8" name="dateModified">
 | 
			
		||||
    <column id="51" parent="8" name="dateModified">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="47" parent="8" name="hash">
 | 
			
		||||
    <column id="52" parent="8" name="hash">
 | 
			
		||||
      <Position>9</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="48" parent="8" name="dateCreated">
 | 
			
		||||
    <column id="53" parent="8" name="dateCreated">
 | 
			
		||||
      <Position>10</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'1970-01-01T00:00:00.000Z'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="49" parent="8" name="sqlite_autoindex_branches_1">
 | 
			
		||||
    <index id="54" parent="8" name="sqlite_autoindex_branches_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>branchId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="50" parent="8" name="IDX_branches_noteId_parentNoteId">
 | 
			
		||||
    <index id="55" parent="8" name="IDX_branches_noteId_parentNoteId">
 | 
			
		||||
      <ColNames>noteId
 | 
			
		||||
parentNoteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="51" parent="8" name="IDX_branches_noteId">
 | 
			
		||||
    <index id="56" parent="8" name="IDX_branches_noteId">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="52" parent="8" name="IDX_branches_parentNoteId">
 | 
			
		||||
    <index id="57" parent="8" name="IDX_branches_parentNoteId">
 | 
			
		||||
      <ColNames>parentNoteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="53" parent="8">
 | 
			
		||||
    <key id="58" parent="8">
 | 
			
		||||
      <ColNames>branchId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_branches_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="54" parent="9" name="eventId">
 | 
			
		||||
    <column id="59" parent="9" name="eventId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="55" parent="9" name="noteId">
 | 
			
		||||
    <column id="60" parent="9" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="56" parent="9" name="comment">
 | 
			
		||||
    <column id="61" parent="9" name="comment">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="57" parent="9" name="dateCreated">
 | 
			
		||||
    <column id="62" parent="9" name="dateCreated">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="58" parent="9" name="sqlite_autoindex_event_log_1">
 | 
			
		||||
    <index id="63" parent="9" name="sqlite_autoindex_event_log_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>eventId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="59" parent="9">
 | 
			
		||||
    <key id="64" parent="9">
 | 
			
		||||
      <ColNames>eventId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_event_log_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="60" parent="10" name="linkId">
 | 
			
		||||
    <column id="65" parent="10" name="linkId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="61" parent="10" name="noteId">
 | 
			
		||||
    <column id="66" parent="10" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="62" parent="10" name="targetNoteId">
 | 
			
		||||
    <column id="67" parent="10" name="targetNoteId">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="63" parent="10" name="type">
 | 
			
		||||
    <column id="68" parent="10" name="type">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="64" parent="10" name="isDeleted">
 | 
			
		||||
    <column id="69" parent="10" name="hash">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="65" parent="10" name="dateCreated">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="66" parent="10" name="dateModified">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="67" parent="10" name="hash">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="68" parent="10" name="sqlite_autoindex_links_1">
 | 
			
		||||
    <column id="70" parent="10" name="isDeleted">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="71" parent="10" name="dateCreated">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="72" parent="10" name="dateModified">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="73" parent="10" name="sqlite_autoindex_links_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>linkId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="69" parent="10">
 | 
			
		||||
    <index id="74" parent="10" name="IDX_links_noteId_index">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="75" parent="10" name="IDX_links_targetNoteId_index">
 | 
			
		||||
      <ColNames>targetNoteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="76" parent="10">
 | 
			
		||||
      <ColNames>linkId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_links_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="70" parent="11" name="noteRevisionId">
 | 
			
		||||
    <column id="77" parent="11" name="noteContentId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="71" parent="11" name="noteId">
 | 
			
		||||
    <column id="78" parent="11" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="72" parent="11" name="title">
 | 
			
		||||
    <column id="79" parent="11" name="isProtected">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="80" parent="11" name="content">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <DefaultExpression>NULL</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="81" parent="11" name="hash">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="82" parent="11" name="dateCreated">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'2018-05-08T23:41:15.225Z'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="83" parent="11" name="dateModified">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'2018-05-08T23:41:15.225Z'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="84" parent="11" name="sqlite_autoindex_note_contents_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>noteContentId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="85" parent="11" name="IDX_note_contents_noteId">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="86" parent="11">
 | 
			
		||||
      <ColNames>noteContentId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_note_contents_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="87" parent="12" name="noteRevisionId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="88" parent="12" name="noteId">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="89" parent="12" name="title">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="73" parent="11" name="content">
 | 
			
		||||
    <column id="90" parent="12" name="content">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="74" parent="11" name="isProtected">
 | 
			
		||||
    <column id="91" parent="12" name="isProtected">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="75" parent="11" name="dateModifiedFrom">
 | 
			
		||||
    <column id="92" parent="12" name="dateModifiedFrom">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="76" parent="11" name="dateModifiedTo">
 | 
			
		||||
    <column id="93" parent="12" name="dateModifiedTo">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="77" parent="11" name="type">
 | 
			
		||||
    <column id="94" parent="12" name="type">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>''</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="78" parent="11" name="mime">
 | 
			
		||||
    <column id="95" parent="12" name="mime">
 | 
			
		||||
      <Position>9</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>''</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="79" parent="11" name="hash">
 | 
			
		||||
    <column id="96" parent="12" name="hash">
 | 
			
		||||
      <Position>10</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="80" parent="11" name="sqlite_autoindex_note_revisions_1">
 | 
			
		||||
    <index id="97" parent="12" name="sqlite_autoindex_note_revisions_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>noteRevisionId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="81" parent="11" name="IDX_note_revisions_noteId">
 | 
			
		||||
    <index id="98" parent="12" name="IDX_note_revisions_noteId">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="82" parent="11" name="IDX_note_revisions_dateModifiedFrom">
 | 
			
		||||
    <index id="99" parent="12" name="IDX_note_revisions_dateModifiedFrom">
 | 
			
		||||
      <ColNames>dateModifiedFrom</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="83" parent="11" name="IDX_note_revisions_dateModifiedTo">
 | 
			
		||||
    <index id="100" parent="12" name="IDX_note_revisions_dateModifiedTo">
 | 
			
		||||
      <ColNames>dateModifiedTo</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="84" parent="11">
 | 
			
		||||
    <key id="101" parent="12">
 | 
			
		||||
      <ColNames>noteRevisionId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_note_revisions_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="85" parent="12" name="noteId">
 | 
			
		||||
    <column id="102" parent="13" name="noteId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="86" parent="12" name="title">
 | 
			
		||||
    <column id="103" parent="13" name="title">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>"note"</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="87" parent="12" name="content">
 | 
			
		||||
    <column id="104" parent="13" name="isProtected">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <DefaultExpression>NULL</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="88" parent="12" name="isProtected">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="89" parent="12" name="type">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
    <column id="105" parent="13" name="type">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'text'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="90" parent="12" name="mime">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
    <column id="106" parent="13" name="mime">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'text/html'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="91" parent="12" name="hash">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
    <column id="107" parent="13" name="hash">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="92" parent="12" name="isDeleted">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
    <column id="108" parent="13" name="isDeleted">
 | 
			
		||||
      <Position>7</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="93" parent="12" name="dateCreated">
 | 
			
		||||
    <column id="109" parent="13" name="dateCreated">
 | 
			
		||||
      <Position>8</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="110" parent="13" name="dateModified">
 | 
			
		||||
      <Position>9</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="94" parent="12" name="dateModified">
 | 
			
		||||
      <Position>10</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="95" parent="12" name="sqlite_autoindex_notes_1">
 | 
			
		||||
    <index id="111" parent="13" name="sqlite_autoindex_notes_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="96" parent="12">
 | 
			
		||||
    <key id="112" parent="13">
 | 
			
		||||
      <ColNames>noteId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_notes_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="97" parent="13" name="name">
 | 
			
		||||
    <column id="113" parent="14" name="name">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="98" parent="13" name="value">
 | 
			
		||||
    <column id="114" parent="14" name="value">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="99" parent="13" name="dateModified">
 | 
			
		||||
    <column id="115" parent="14" name="dateModified">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="100" parent="13" name="isSynced">
 | 
			
		||||
    <column id="116" parent="14" name="isSynced">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>0</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="101" parent="13" name="hash">
 | 
			
		||||
    <column id="117" parent="14" name="hash">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="102" parent="13" name="dateCreated">
 | 
			
		||||
    <column id="118" parent="14" name="dateCreated">
 | 
			
		||||
      <Position>6</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>'1970-01-01T00:00:00.000Z'</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="103" parent="13" name="sqlite_autoindex_options_1">
 | 
			
		||||
    <index id="119" parent="14" name="sqlite_autoindex_options_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>name</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="104" parent="13">
 | 
			
		||||
    <key id="120" parent="14">
 | 
			
		||||
      <ColNames>name</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_options_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="105" parent="14" name="branchId">
 | 
			
		||||
    <column id="121" parent="15" name="branchId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="106" parent="14" name="notePath">
 | 
			
		||||
    <column id="122" parent="15" name="notePath">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="107" parent="14" name="hash">
 | 
			
		||||
    <column id="123" parent="15" name="hash">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <DefaultExpression>""</DefaultExpression>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="108" parent="14" name="dateCreated">
 | 
			
		||||
    <column id="124" parent="15" name="dateCreated">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="109" parent="14" name="isDeleted">
 | 
			
		||||
    <column id="125" parent="15" name="isDeleted">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>INT|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="110" parent="14" name="sqlite_autoindex_recent_notes_1">
 | 
			
		||||
    <index id="126" parent="15" name="sqlite_autoindex_recent_notes_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>branchId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="111" parent="14">
 | 
			
		||||
    <key id="127" parent="15">
 | 
			
		||||
      <ColNames>branchId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_recent_notes_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="112" parent="15" name="sourceId">
 | 
			
		||||
    <column id="128" parent="16" name="sourceId">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="113" parent="15" name="dateCreated">
 | 
			
		||||
    <column id="129" parent="16" name="dateCreated">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="114" parent="15" name="sqlite_autoindex_source_ids_1">
 | 
			
		||||
    <index id="130" parent="16" name="sqlite_autoindex_source_ids_1">
 | 
			
		||||
      <NameSurrogate>1</NameSurrogate>
 | 
			
		||||
      <ColNames>sourceId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="115" parent="15">
 | 
			
		||||
    <key id="131" parent="16">
 | 
			
		||||
      <ColNames>sourceId</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
      <UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName>
 | 
			
		||||
    </key>
 | 
			
		||||
    <column id="116" parent="16" name="type">
 | 
			
		||||
    <column id="132" parent="17" name="type">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>text|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="117" parent="16" name="name">
 | 
			
		||||
    <column id="133" parent="17" name="name">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>text|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="118" parent="16" name="tbl_name">
 | 
			
		||||
    <column id="134" parent="17" name="tbl_name">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>text|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="119" parent="16" name="rootpage">
 | 
			
		||||
    <column id="135" parent="17" name="rootpage">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>integer|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="120" parent="16" name="sql">
 | 
			
		||||
    <column id="136" parent="17" name="sql">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>text|0s</DataType>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="121" parent="17" name="name">
 | 
			
		||||
    <column id="137" parent="18" name="name">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="122" parent="17" name="seq">
 | 
			
		||||
    <column id="138" parent="18" name="seq">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="123" parent="18" name="id">
 | 
			
		||||
    <column id="139" parent="19" name="id">
 | 
			
		||||
      <Position>1</Position>
 | 
			
		||||
      <DataType>INTEGER|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
      <SequenceIdentity>1</SequenceIdentity>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="124" parent="18" name="entityName">
 | 
			
		||||
    <column id="140" parent="19" name="entityName">
 | 
			
		||||
      <Position>2</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="125" parent="18" name="entityId">
 | 
			
		||||
    <column id="141" parent="19" name="entityId">
 | 
			
		||||
      <Position>3</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="126" parent="18" name="sourceId">
 | 
			
		||||
    <column id="142" parent="19" name="sourceId">
 | 
			
		||||
      <Position>4</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <column id="127" parent="18" name="syncDate">
 | 
			
		||||
    <column id="143" parent="19" name="syncDate">
 | 
			
		||||
      <Position>5</Position>
 | 
			
		||||
      <DataType>TEXT|0s</DataType>
 | 
			
		||||
      <NotNull>1</NotNull>
 | 
			
		||||
    </column>
 | 
			
		||||
    <index id="128" parent="18" name="IDX_sync_entityName_entityId">
 | 
			
		||||
    <index id="144" parent="19" name="IDX_sync_entityName_entityId">
 | 
			
		||||
      <ColNames>entityName
 | 
			
		||||
entityId</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
      <Unique>1</Unique>
 | 
			
		||||
    </index>
 | 
			
		||||
    <index id="129" parent="18" name="IDX_sync_syncDate">
 | 
			
		||||
    <index id="145" parent="19" name="IDX_sync_syncDate">
 | 
			
		||||
      <ColNames>syncDate</ColNames>
 | 
			
		||||
      <ColumnCollations></ColumnCollations>
 | 
			
		||||
    </index>
 | 
			
		||||
    <key id="130" parent="18">
 | 
			
		||||
    <key id="146" parent="19">
 | 
			
		||||
      <ColNames>id</ColNames>
 | 
			
		||||
      <Primary>1</Primary>
 | 
			
		||||
    </key>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
FROM node:10.14.0-alpine
 | 
			
		||||
FROM node:10.15.0-alpine
 | 
			
		||||
 | 
			
		||||
# Create app directory
 | 
			
		||||
WORKDIR /usr/src/app
 | 
			
		||||
@@ -17,6 +17,7 @@ RUN set -x \
 | 
			
		||||
        libtool \
 | 
			
		||||
        make \
 | 
			
		||||
        nasm \
 | 
			
		||||
        libpng-dev \
 | 
			
		||||
    && npm install --production \
 | 
			
		||||
    && apk del .build-dependencies
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							@@ -10,7 +10,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l
 | 
			
		||||
* 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)
 | 
			
		||||
* 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)
 | 
			
		||||
* 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)
 | 
			
		||||
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
 | 
			
		||||
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
 | 
			
		||||
@@ -18,6 +18,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l
 | 
			
		||||
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) for visualizing notes and their relations
 | 
			
		||||
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
 | 
			
		||||
* Scales well in both usability and performance upwards of 100 000 notes
 | 
			
		||||
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
 | 
			
		||||
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
 | 
			
		||||
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
 | 
			
		||||
 | 
			
		||||
@@ -34,3 +35,15 @@ Trilium is provided as either desktop application (Linux, Windows, Mac) or web a
 | 
			
		||||
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
 | 
			
		||||
 | 
			
		||||
You can also read [Patterns of personal knowledge base](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base) to get some inspiration on how you might use Trilium.
 | 
			
		||||
 | 
			
		||||
## Contribute
 | 
			
		||||
 | 
			
		||||
Use a browser based dev environment
 | 
			
		||||
 | 
			
		||||
[](https://gitpod.io/#https://github.com/zadam/trilium)
 | 
			
		||||
 | 
			
		||||
Or clone locally and run
 | 
			
		||||
```
 | 
			
		||||
npm install
 | 
			
		||||
npm run start
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										7
									
								
								bin/build-debian.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								bin/build-debian.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
echo "Packaging debian x64 distribution..."
 | 
			
		||||
 | 
			
		||||
VERSION=`jq -r ".version" package.json`
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-installer-debian --config bin/deb-options.json --options.version=${VERSION} --arch amd64
 | 
			
		||||
@@ -3,22 +3,22 @@
 | 
			
		||||
BUILD_DIR=./dist/trilium-linux-x64
 | 
			
		||||
rm -rf $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
# we build x64 as second so that we keep X64 binaries in node_modules for local development and server build
 | 
			
		||||
echo "Rebuilding binaries for linux-x64"
 | 
			
		||||
./node_modules/.bin/electron-rebuild --arch=x64
 | 
			
		||||
rm -r node_modules/sqlite3/lib/binding/*
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
 | 
			
		||||
cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
 | 
			
		||||
 | 
			
		||||
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
rm -r "$BUILD_DIR/resources/app/node_modules/sqlite3/lib/binding/*"
 | 
			
		||||
cp src/public/images/app-icons/png/128x128.png $BUILD_DIR/icon.png
 | 
			
		||||
 | 
			
		||||
cp -r bin/deps/linux-x64/sqlite/electron* "$BUILD_DIR/resources/app/node_modules/sqlite3/lib/binding/"
 | 
			
		||||
 | 
			
		||||
rm -r $BUILD_DIR/resources/app/bin/deps
 | 
			
		||||
# removing software WebGL binaries because they are pretty huge and not necessary
 | 
			
		||||
rm -r $BUILD_DIR/swiftshader
 | 
			
		||||
 | 
			
		||||
echo "Packaging linux x64 electron distribution..."
 | 
			
		||||
VERSION=`jq -r ".version" package.json`
 | 
			
		||||
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
cd dist
 | 
			
		||||
 | 
			
		||||
tar cJf trilium-linux-x64-${VERSION}.tar.xz trilium-linux-x64
 | 
			
		||||
 
 | 
			
		||||
@@ -3,25 +3,30 @@
 | 
			
		||||
BUILD_DIR=./dist/trilium-mac-x64
 | 
			
		||||
rm -rf $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=darwin  --arch=x64 --overwrite --icon=src/public/images/app-icons/mac/icon.icns
 | 
			
		||||
echo "Copying required mac binaries"
 | 
			
		||||
 | 
			
		||||
rm -r node_modules/sqlite3/lib/binding/*
 | 
			
		||||
rm -r node_modules/mozjpeg/vendor/*
 | 
			
		||||
rm -r node_modules/pngquant-bin/vendor/*
 | 
			
		||||
rm -r node_modules/giflossy/vendor/*
 | 
			
		||||
 | 
			
		||||
cp -r bin/deps/mac-x64/sqlite/* node_modules/sqlite3/lib/binding/
 | 
			
		||||
cp bin/deps/mac-x64/image/cjpeg node_modules/mozjpeg/vendor/
 | 
			
		||||
cp bin/deps/mac-x64/image/pngquant node_modules/pngquant-bin/vendor/
 | 
			
		||||
cp bin/deps/mac-x64/image/gifsicle node_modules/giflossy/vendor/
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=src/public/images/app-icons/mac/icon.icns
 | 
			
		||||
 | 
			
		||||
# Mac build has by default useless directory level
 | 
			
		||||
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
echo "Copying required mac binaries"
 | 
			
		||||
./bin/reset-local.sh
 | 
			
		||||
 | 
			
		||||
MAC_RES_DIR=$BUILD_DIR/Trilium\ Notes.app/Contents/Resources/app
 | 
			
		||||
 | 
			
		||||
rm -r "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/*"
 | 
			
		||||
 | 
			
		||||
cp -r bin/deps/mac-x64/sqlite/* "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/"
 | 
			
		||||
cp bin/deps/mac-x64/image/cjpeg "$MAC_RES_DIR/node_modules/mozjpeg/vendor/"
 | 
			
		||||
cp bin/deps/mac-x64/image/pngquant "$MAC_RES_DIR/node_modules/pngquant-bin/vendor/"
 | 
			
		||||
cp bin/deps/mac-x64/image/gifsicle "$MAC_RES_DIR/node_modules/giflossy/vendor/"
 | 
			
		||||
 | 
			
		||||
rm -r "$MAC_RES_DIR/bin/deps"
 | 
			
		||||
 | 
			
		||||
echo "Packaging mac x64 electron distribution..."
 | 
			
		||||
echo "Zipping mac x64 electron distribution..."
 | 
			
		||||
 | 
			
		||||
VERSION=`jq -r ".version" package.json`
 | 
			
		||||
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
cd dist
 | 
			
		||||
 | 
			
		||||
rm trilium-mac-x64-${VERSION}.zip
 | 
			
		||||
zip -r9 --symlinks trilium-mac-x64-${VERSION}.zip trilium-mac-x64
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
PKG_DIR=dist/trilium-linux-x64-server
 | 
			
		||||
NODE_VERSION=10.14.1
 | 
			
		||||
NODE_VERSION=10.15.0
 | 
			
		||||
 | 
			
		||||
rm -r $PKG_DIR
 | 
			
		||||
mkdir $PKG_DIR
 | 
			
		||||
@@ -34,4 +34,5 @@ chmod 755 trilium.sh
 | 
			
		||||
cd ..
 | 
			
		||||
 | 
			
		||||
VERSION=`jq -r ".version" ../package.json`
 | 
			
		||||
7z a trilium-linux-x64-server-${VERSION}.7z trilium-linux-x64-server
 | 
			
		||||
 | 
			
		||||
tar cJf trilium-linux-x64-server-${VERSION}.tar.xz trilium-linux-x64-server
 | 
			
		||||
@@ -3,23 +3,30 @@
 | 
			
		||||
BUILD_DIR=./dist/trilium-windows-x64
 | 
			
		||||
rm -rf $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=win32  --arch=x64 --overwrite --icon=src/public/images/app-icons/win/icon.ico
 | 
			
		||||
echo "Copying required windows binaries"
 | 
			
		||||
 | 
			
		||||
rm -r node_modules/sqlite3/lib/binding/*
 | 
			
		||||
rm -r node_modules/mozjpeg/vendor/*
 | 
			
		||||
rm -r node_modules/pngquant-bin/vendor/*
 | 
			
		||||
rm -r node_modules/giflossy/vendor/*
 | 
			
		||||
 | 
			
		||||
cp -r bin/deps/win-x64/sqlite/* node_modules/sqlite3/lib/binding/
 | 
			
		||||
cp bin/deps/win-x64/image/cjpeg.exe node_modules/mozjpeg/vendor/
 | 
			
		||||
cp bin/deps/win-x64/image/pngquant.exe node_modules/pngquant-bin/vendor/
 | 
			
		||||
cp bin/deps/win-x64/image/gifsicle.exe node_modules/giflossy/vendor/
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=win32  --arch=x64 --overwrite --icon=src/public/images/app-icons/win/icon.ico
 | 
			
		||||
 | 
			
		||||
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
echo "Copying required windows binaries"
 | 
			
		||||
 | 
			
		||||
WIN_RES_DIR=$BUILD_DIR/resources/app
 | 
			
		||||
 | 
			
		||||
cp -r bin/deps/win-x64/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
 | 
			
		||||
cp bin/deps/win-x64/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
 | 
			
		||||
cp bin/deps/win-x64/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
 | 
			
		||||
cp bin/deps/win-x64/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
 | 
			
		||||
 | 
			
		||||
rm -r $WIN_RES_DIR/bin/deps
 | 
			
		||||
# removing software WebGL binaries because they are pretty huge and not necessary
 | 
			
		||||
rm -r $BUILD_DIR/swiftshader
 | 
			
		||||
 | 
			
		||||
echo "Packaging windows x64 electron distribution..."
 | 
			
		||||
./bin/reset-local.sh
 | 
			
		||||
 | 
			
		||||
echo "Zipping windows x64 electron distribution..."
 | 
			
		||||
VERSION=`jq -r ".version" package.json`
 | 
			
		||||
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR
 | 
			
		||||
 | 
			
		||||
cd dist
 | 
			
		||||
 | 
			
		||||
zip -r9 trilium-windows-x64-${VERSION}.zip trilium-windows-x64
 | 
			
		||||
 
 | 
			
		||||
@@ -15,4 +15,7 @@ bin/build-mac-x64.sh
 | 
			
		||||
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development
 | 
			
		||||
bin/build-linux-x64.sh
 | 
			
		||||
 | 
			
		||||
# this needs to be run after linux build
 | 
			
		||||
bin/build-debian.sh
 | 
			
		||||
 | 
			
		||||
bin/build-server.sh
 | 
			
		||||
							
								
								
									
										14
									
								
								bin/deb-options.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								bin/deb-options.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
{
 | 
			
		||||
  "src": "dist/trilium-linux-x64",
 | 
			
		||||
  "dest": "dist/",
 | 
			
		||||
  "name": "trilium",
 | 
			
		||||
  "productName": "Trilium Notes",
 | 
			
		||||
  "genericName": "Note taker",
 | 
			
		||||
  "description": "Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases.",
 | 
			
		||||
  "sections": "misc",
 | 
			
		||||
  "maintainer": "zadam.apps@gmail.com",
 | 
			
		||||
  "homepage": "https://github.com/zadam/trilium",
 | 
			
		||||
  "bin": "trilium",
 | 
			
		||||
  "icon": "dist/trilium-linux-x64/icon.png",
 | 
			
		||||
  "categories": [ "Office" ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								bin/deps/mac-x64/image/cjpeg
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								bin/deps/mac-x64/image/cjpeg
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
								
								
									
										0
									
								
								bin/deps/win-x64/image/cjpeg.exe
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										0
									
								
								bin/deps/win-x64/image/cjpeg.exe
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -42,10 +42,11 @@ git push origin $TAG
 | 
			
		||||
 | 
			
		||||
bin/build.sh
 | 
			
		||||
 | 
			
		||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.7z
 | 
			
		||||
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.7z
 | 
			
		||||
MAC_X64_BUILD=trilium-mac-x64-$VERSION.7z
 | 
			
		||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.7z
 | 
			
		||||
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.tar.xz
 | 
			
		||||
DEBIAN_X64_BUILD=trilium_${VERSION}_amd64.deb
 | 
			
		||||
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.zip
 | 
			
		||||
MAC_X64_BUILD=trilium-mac-x64-$VERSION.zip
 | 
			
		||||
SERVER_BUILD=trilium-linux-x64-server-$VERSION.tar.xz
 | 
			
		||||
 | 
			
		||||
echo "Creating release in GitHub"
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +60,13 @@ github-release release \
 | 
			
		||||
    --tag $TAG \
 | 
			
		||||
    --name "$TAG release" $EXTRA
 | 
			
		||||
 | 
			
		||||
echo "Uploading debian x64 package"
 | 
			
		||||
 | 
			
		||||
github-release upload \
 | 
			
		||||
    --tag $TAG \
 | 
			
		||||
    --name "$DEBIAN_X64_BUILD" \
 | 
			
		||||
    --file "dist/$DEBIAN_X64_BUILD"
 | 
			
		||||
 | 
			
		||||
echo "Uploading linux x64 build"
 | 
			
		||||
 | 
			
		||||
github-release upload \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								bin/reset-local.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								bin/reset-local.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
./node_modules/.bin/electron-rebuild --arch=x64
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								db/demo.tar
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								db/demo.tar
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								db/migrations/0121__add_hoisting_option.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								db/migrations/0121__add_hoisting_option.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
VALUES ('hoistedNoteId', 'root', '2018-12-11T18:31:00.874Z', '2018-12-11T18:31:00.874Z', 0);
 | 
			
		||||
							
								
								
									
										62
									
								
								db/migrations/0122__add_iv_to_columns.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								db/migrations/0122__add_iv_to_columns.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
const sql = require('../../src/services/sql');
 | 
			
		||||
 | 
			
		||||
function prependIv(cipherText, ivText) {
 | 
			
		||||
    const arr = ivText.split("").map(c => parseInt(c) || 0);
 | 
			
		||||
    const iv = Buffer.from(arr);
 | 
			
		||||
    const payload = Buffer.from(cipherText, 'base64');
 | 
			
		||||
    const complete = Buffer.concat([iv, payload]);
 | 
			
		||||
 | 
			
		||||
    return complete.toString('base64');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function updateEncryptedDataKey() {
 | 
			
		||||
    const encryptedDataKey = await sql.getValue("SELECT value FROM options WHERE name = 'encryptedDataKey'");
 | 
			
		||||
    const encryptedDataKeyIv = await sql.getValue("SELECT value FROM options WHERE name = 'encryptedDataKeyIv'");
 | 
			
		||||
 | 
			
		||||
    const newEncryptedDataKey = prependIv(encryptedDataKey, encryptedDataKeyIv);
 | 
			
		||||
 | 
			
		||||
    await sql.execute("UPDATE options SET value = ? WHERE name = 'encryptedDataKey'", [newEncryptedDataKey]);
 | 
			
		||||
 | 
			
		||||
    await sql.execute("DELETE FROM options WHERE name = 'encryptedDataKeyIv'");
 | 
			
		||||
    await sql.execute("DELETE FROM sync WHERE entityName = 'options' AND entityId = 'encryptedDataKeyIv'");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function updateNotes() {
 | 
			
		||||
    const protectedNotes = await sql.getRows("SELECT noteId, title, content FROM notes WHERE isProtected = 1");
 | 
			
		||||
 | 
			
		||||
    for (const note of protectedNotes) {
 | 
			
		||||
        if (note.title !== null) {
 | 
			
		||||
            note.title = prependIv(note.title, "0" + note.noteId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (note.content !== null) {
 | 
			
		||||
            note.content = prependIv(note.content, "1" + note.noteId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await sql.execute("UPDATE notes SET title = ?, content = ? WHERE noteId = ?", [note.title, note.content, note.noteId]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function updateNoteRevisions() {
 | 
			
		||||
    const protectedNoteRevisions = await sql.getRows("SELECT noteRevisionId, title, content FROM note_revisions WHERE isProtected = 1");
 | 
			
		||||
 | 
			
		||||
    for (const noteRevision of protectedNoteRevisions) {
 | 
			
		||||
        if (noteRevision.title !== null) {
 | 
			
		||||
            noteRevision.title = prependIv(noteRevision.title, "0" + noteRevision.noteRevisionId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (noteRevision.content !== null) {
 | 
			
		||||
            noteRevision.content = prependIv(noteRevision.content, "1" + noteRevision.noteRevisionId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await sql.execute("UPDATE note_revisions SET title = ?, content = ? WHERE noteRevisionId = ?", [noteRevision.title, noteRevision.content, noteRevision.noteRevisionId]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = async () => {
 | 
			
		||||
    await updateEncryptedDataKey();
 | 
			
		||||
 | 
			
		||||
    await updateNotes();
 | 
			
		||||
 | 
			
		||||
    await updateNoteRevisions();
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										8
									
								
								db/migrations/0123__add_options_for_font_sizes.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								db/migrations/0123__add_options_for_font_sizes.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
VALUES ('mainFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
 | 
			
		||||
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
VALUES ('treeFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
 | 
			
		||||
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
VALUES ('detailFontSize', '110', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0);
 | 
			
		||||
							
								
								
									
										11
									
								
								db/migrations/0124__readd_font_sizes.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								db/migrations/0124__readd_font_sizes.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
  SELECT 'mainFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
 | 
			
		||||
    WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'mainFontSize');
 | 
			
		||||
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
  SELECT 'treeFontSize', '100', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
 | 
			
		||||
    WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'treeFontSize');
 | 
			
		||||
 | 
			
		||||
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
 | 
			
		||||
  SELECT 'detailFontSize', '110', '2019-01-13T18:31:00.874Z', '2019-01-13T18:31:00.874Z', 0
 | 
			
		||||
    WHERE NOT EXISTS (SELECT 1 FROM options WHERE name = 'detailFontSize');
 | 
			
		||||
							
								
								
									
										35
									
								
								db/migrations/0125__create_note_content_table.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								db/migrations/0125__create_note_content_table.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "note_contents" (
 | 
			
		||||
  `noteContentId`	TEXT NOT NULL,
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
  `isProtected`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `content`	TEXT NULL DEFAULT NULL,
 | 
			
		||||
  `hash` TEXT DEFAULT "" NOT NULL,
 | 
			
		||||
  `dateCreated`	TEXT NOT NULL,
 | 
			
		||||
  `dateModified` TEXT NOT NULL,
 | 
			
		||||
  PRIMARY KEY(`noteContentId`)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE UNIQUE INDEX `IDX_note_contents_noteId` ON `note_contents` (`noteId`);
 | 
			
		||||
 | 
			
		||||
INSERT INTO note_contents (noteContentId, noteId, isProtected, content, dateCreated, dateModified)
 | 
			
		||||
  SELECT 'C' || SUBSTR(noteId, 2), noteId, isProtected, content, dateCreated, dateModified FROM notes;
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "notes_mig" (
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
  `title`	TEXT NOT NULL DEFAULT "note",
 | 
			
		||||
  `isProtected`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `type` TEXT NOT NULL DEFAULT 'text',
 | 
			
		||||
  `mime` TEXT NOT NULL DEFAULT 'text/html',
 | 
			
		||||
  `hash` TEXT DEFAULT "" NOT NULL,
 | 
			
		||||
  `isDeleted`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `dateCreated`	TEXT NOT NULL,
 | 
			
		||||
  `dateModified`	TEXT NOT NULL,
 | 
			
		||||
  PRIMARY KEY(`noteId`)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
INSERT INTO notes_mig (noteId, title, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash)
 | 
			
		||||
SELECT noteId, title, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash FROM notes;
 | 
			
		||||
 | 
			
		||||
DROP TABLE notes;
 | 
			
		||||
 | 
			
		||||
ALTER TABLE notes_mig RENAME TO notes;
 | 
			
		||||
							
								
								
									
										2
									
								
								db/migrations/0126__fill_sync_for_note_contents.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								db/migrations/0126__fill_sync_for_note_contents.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
INSERT OR REPLACE INTO sync (entityName, entityId, sourceId, syncDate)
 | 
			
		||||
SELECT 'note_contents', noteContentId, '', '2019-03-02T18:07:29.182Z' FROM note_contents;
 | 
			
		||||
							
								
								
									
										6
									
								
								db/migrations/0127__fix_inconsistent_isProtected.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								db/migrations/0127__fix_inconsistent_isProtected.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
UPDATE notes SET title = 'Recovered protected note', isProtected = 0 WHERE noteId IN (
 | 
			
		||||
    SELECT noteId FROM notes JOIN note_contents USING(noteId)
 | 
			
		||||
    WHERE notes.isProtected = 1
 | 
			
		||||
      AND note_contents.isProtected = 0
 | 
			
		||||
      AND notes.isDeleted = 0
 | 
			
		||||
)
 | 
			
		||||
@@ -96,19 +96,6 @@ CREATE TABLE attributes
 | 
			
		||||
  hash         TEXT default "" not null, isInheritable int DEFAULT 0 NULL);
 | 
			
		||||
CREATE INDEX IDX_attributes_name_value
 | 
			
		||||
  on attributes (name, value);
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "notes" (
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
  `title`	TEXT NOT NULL DEFAULT "note",
 | 
			
		||||
  `content`	TEXT NULL DEFAULT NULL,
 | 
			
		||||
  `isProtected`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `type` TEXT NOT NULL DEFAULT 'text',
 | 
			
		||||
  `mime` TEXT NOT NULL DEFAULT 'text/html',
 | 
			
		||||
  `hash` TEXT DEFAULT "" NOT NULL,
 | 
			
		||||
  `isDeleted`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `dateCreated`	TEXT NOT NULL,
 | 
			
		||||
  `dateModified`	TEXT NOT NULL,
 | 
			
		||||
  PRIMARY KEY(`noteId`)
 | 
			
		||||
);
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "links" (
 | 
			
		||||
  `linkId`	TEXT NOT NULL,
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
@@ -130,3 +117,26 @@ CREATE INDEX IDX_attributes_noteId_index
 | 
			
		||||
  on attributes (noteId);
 | 
			
		||||
CREATE INDEX IDX_attributes_value_index
 | 
			
		||||
  on attributes (value);
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "note_contents" (
 | 
			
		||||
  `noteContentId`	TEXT NOT NULL,
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
  `isProtected`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `content`	TEXT NULL DEFAULT NULL,
 | 
			
		||||
  `hash` TEXT DEFAULT "" NOT NULL,
 | 
			
		||||
  `dateCreated`	TEXT NOT NULL,
 | 
			
		||||
  `dateModified` TEXT NOT NULL,
 | 
			
		||||
  PRIMARY KEY(`noteContentId`)
 | 
			
		||||
);
 | 
			
		||||
CREATE UNIQUE INDEX `IDX_note_contents_noteId` ON `note_contents` (`noteId`);
 | 
			
		||||
CREATE TABLE IF NOT EXISTS "notes" (
 | 
			
		||||
  `noteId`	TEXT NOT NULL,
 | 
			
		||||
  `title`	TEXT NOT NULL DEFAULT "note",
 | 
			
		||||
  `isProtected`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `type` TEXT NOT NULL DEFAULT 'text',
 | 
			
		||||
  `mime` TEXT NOT NULL DEFAULT 'text/html',
 | 
			
		||||
  `hash` TEXT DEFAULT "" NOT NULL,
 | 
			
		||||
  `isDeleted`	INT NOT NULL DEFAULT 0,
 | 
			
		||||
  `dateCreated`	TEXT NOT NULL,
 | 
			
		||||
  `dateModified`	TEXT NOT NULL,
 | 
			
		||||
  PRIMARY KEY(`noteId`)
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -282,7 +282,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -724,7 +724,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -505,7 +505,7 @@ Each note can have multiple (at least one) branches, meaning it can be placed in
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -210,7 +210,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -352,7 +352,7 @@ this is different concept than attribute/relation.</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										494
									
								
								docs/backend_api/NoteContent.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										494
									
								
								docs/backend_api/NoteContent.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,494 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <title>JSDoc: Class: NoteContent</title>
 | 
			
		||||
 | 
			
		||||
    <script src="scripts/prettify/prettify.js"> </script>
 | 
			
		||||
    <script src="scripts/prettify/lang-css.js"> </script>
 | 
			
		||||
    <!--[if lt IE 9]>
 | 
			
		||||
      <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 | 
			
		||||
    <![endif]-->
 | 
			
		||||
    <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
 | 
			
		||||
    <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<div id="main">
 | 
			
		||||
 | 
			
		||||
    <h1 class="page-title">Class: NoteContent</h1>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<section>
 | 
			
		||||
 | 
			
		||||
<header>
 | 
			
		||||
    
 | 
			
		||||
        <h2><span class="attribs"><span class="type-signature"></span></span>NoteContent<span class="signature">(row)</span><span class="type-signature"></span></h2>
 | 
			
		||||
        
 | 
			
		||||
            <div class="class-description">This represents a Note which is a central object in the Trilium Notes project.</div>
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
</header>
 | 
			
		||||
 | 
			
		||||
<article>
 | 
			
		||||
    <div class="container-overview">
 | 
			
		||||
    
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h2>Constructor</h2>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="NoteContent"><span class="type-signature"></span>new NoteContent<span class="signature">(row)</span><span class="type-signature"></span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <h5>Parameters:</h5>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
<table class="params">
 | 
			
		||||
    <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
        
 | 
			
		||||
        <th>Name</th>
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th>Type</th>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th class="last">Description</th>
 | 
			
		||||
    </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
 | 
			
		||||
    <tbody>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>row</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">object containing database row from "note_contents" table</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <h5 class="subsection-title">Properties:</h5>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
<table class="props">
 | 
			
		||||
    <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
        
 | 
			
		||||
        <th>Name</th>
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th>Type</th>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th class="last">Description</th>
 | 
			
		||||
    </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
 | 
			
		||||
    <tbody>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>noteContentId</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">primary key</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>noteId</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">reference to owning note</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>isProtected</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">boolean</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">true if note content is protected</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>content</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">blob</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">note content - e.g. HTML text for text notes, file payload for files</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>dateCreated</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last"></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>dateModified</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last"></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="entities_note_content.js.html">entities/note_content.js</a>, <a href="entities_note_content.js.html#line20">line 20</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
        <h3 class="subsection-title">Extends</h3>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <ul>
 | 
			
		||||
        <li><a href="Entity.html">Entity</a></li>
 | 
			
		||||
    </ul>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
        <h3 class="subsection-title">Methods</h3>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getNote"><span class="type-signature">(async) </span>getNote<span class="signature">()</span><span class="type-signature"> → {Promise.<<a href="Note.html">Note</a>>}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="entities_note_content.js.html">entities/note_content.js</a>, <a href="entities_note_content.js.html#line63">line 63</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h5>Returns:</h5>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl>
 | 
			
		||||
    <dt>
 | 
			
		||||
        Type
 | 
			
		||||
    </dt>
 | 
			
		||||
    <dd>
 | 
			
		||||
        
 | 
			
		||||
<span class="param-type">Promise.<<a href="Note.html">Note</a>></span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dd>
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</article>
 | 
			
		||||
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 | 
			
		||||
<footer>
 | 
			
		||||
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
 | 
			
		||||
</footer>
 | 
			
		||||
 | 
			
		||||
<script> prettyPrint(); </script>
 | 
			
		||||
<script src="scripts/linenumber.js"> </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -397,7 +397,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -305,7 +305,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -282,7 +282,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ module.exports = ApiToken;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -133,6 +133,11 @@ class Attribute extends Entity {
 | 
			
		||||
            this.dateModified = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        delete pojo.isOwned;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Attribute;</code></pre>
 | 
			
		||||
@@ -145,7 +150,7 @@ module.exports = Attribute;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,11 @@ class Branch extends Entity {
 | 
			
		||||
            this.dateModified = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        delete pojo.origParentNoteId;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Branch;</code></pre>
 | 
			
		||||
@@ -99,7 +104,7 @@ module.exports = Branch;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -36,8 +36,11 @@ class Entity {
 | 
			
		||||
     */
 | 
			
		||||
    constructor(row = {}) {
 | 
			
		||||
        for (const key in row) {
 | 
			
		||||
            // ! is used when joint-fetching notes and note_contents objects for performance
 | 
			
		||||
            if (!key.startsWith('!')) {
 | 
			
		||||
                this[key] = row[key];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ('isDeleted' in this) {
 | 
			
		||||
            this.isDeleted = !!this.isDeleted;
 | 
			
		||||
@@ -87,7 +90,7 @@ module.exports = Entity;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ module.exports = Link;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,10 @@
 | 
			
		||||
 | 
			
		||||
const Entity = require('./entity');
 | 
			
		||||
const Attribute = require('./attribute');
 | 
			
		||||
const NoteContent = require('./note_content');
 | 
			
		||||
const protectedSessionService = require('../services/protected_session');
 | 
			
		||||
const repository = require('../services/repository');
 | 
			
		||||
const sql = require('../services/sql');
 | 
			
		||||
const dateUtils = require('../services/date_utils');
 | 
			
		||||
 | 
			
		||||
const LABEL = 'label';
 | 
			
		||||
@@ -39,6 +41,8 @@ const LABEL_DEFINITION = 'label-definition';
 | 
			
		||||
const RELATION = 'relation';
 | 
			
		||||
const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 | 
			
		||||
const STRING_MIME_TYPES = ["application/x-javascript"];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This represents a Note which is a central object in the Trilium Notes project.
 | 
			
		||||
 *
 | 
			
		||||
@@ -46,7 +50,6 @@ const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 * @property {string} type - one of "text", "code", "file" or "render"
 | 
			
		||||
 * @property {string} mime - MIME type, e.g. "text/html"
 | 
			
		||||
 * @property {string} title - note title
 | 
			
		||||
 * @property {string} content - note content - e.g. HTML text for text notes, file payload for files
 | 
			
		||||
 * @property {boolean} isProtected - true if note is protected
 | 
			
		||||
 * @property {boolean} isDeleted - true if note is deleted
 | 
			
		||||
 * @property {string} dateCreated
 | 
			
		||||
@@ -57,7 +60,7 @@ const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
class Note extends Entity {
 | 
			
		||||
    static get entityName() { return "notes"; }
 | 
			
		||||
    static get primaryKeyName() { return "noteId"; }
 | 
			
		||||
    static get hashedProperties() { return ["noteId", "title", "content", "type", "isProtected", "isDeleted"]; }
 | 
			
		||||
    static get hashedProperties() { return ["noteId", "title", "type", "isProtected", "isDeleted"]; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param row - object containing database row from "notes" table
 | 
			
		||||
@@ -74,19 +77,64 @@ class Note extends Entity {
 | 
			
		||||
        if (this.isProtected && this.noteId) {
 | 
			
		||||
            this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
 | 
			
		||||
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.decryptNote(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        this.setContent(this.content);
 | 
			
		||||
            else {
 | 
			
		||||
                // saving ciphertexts in case we do want to update protected note outside of protected session
 | 
			
		||||
                // (which is allowed)
 | 
			
		||||
                this.titleCipherText = this.title;
 | 
			
		||||
                this.title = "[protected]";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setContent(content) {
 | 
			
		||||
        this.content = content;
 | 
			
		||||
    /** @returns {Promise<NoteContent>} */
 | 
			
		||||
    async getNoteContent() {
 | 
			
		||||
        if (!this.noteContent) {
 | 
			
		||||
            this.noteContent = await repository.getEntity(`SELECT * FROM note_contents WHERE noteId = ?`, [this.noteId]);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            this.jsonContent = JSON.parse(this.content);
 | 
			
		||||
            if (!this.noteContent) {
 | 
			
		||||
                throw new Error("Note content not found for noteId=" + this.noteId);
 | 
			
		||||
            }
 | 
			
		||||
        catch(e) {}
 | 
			
		||||
 | 
			
		||||
            if (this.isStringNote()) {
 | 
			
		||||
                this.noteContent.content = this.noteContent.content.toString("UTF-8");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.noteContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise<*>} */
 | 
			
		||||
    async getContent() {
 | 
			
		||||
        const noteContent = await this.getNoteContent();
 | 
			
		||||
 | 
			
		||||
        return noteContent.content;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise<*>} */
 | 
			
		||||
    async getJsonContent() {
 | 
			
		||||
        const content = await this.getContent();
 | 
			
		||||
 | 
			
		||||
        return JSON.parse(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise} */
 | 
			
		||||
    async setContent(content) {
 | 
			
		||||
        if (!this.noteContent) {
 | 
			
		||||
            // make sure it is loaded
 | 
			
		||||
            await this.getNoteContent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.noteContent.content = content;
 | 
			
		||||
 | 
			
		||||
        await this.noteContent.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise} */
 | 
			
		||||
    async setJsonContent(content) {
 | 
			
		||||
        await this.setContent(JSON.stringify(content, null, '\t'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {boolean} true if this note is the root of the note tree. Root note has "root" noteId */
 | 
			
		||||
@@ -102,7 +150,9 @@ class Note extends Entity {
 | 
			
		||||
    /** @returns {boolean} true if this note is JavaScript (code or attachment) */
 | 
			
		||||
    isJavaScript() {
 | 
			
		||||
        return (this.type === "code" || this.type === "file")
 | 
			
		||||
            && (this.mime.startsWith("application/javascript") || this.mime === "application/x-javascript");
 | 
			
		||||
            && (this.mime.startsWith("application/javascript")
 | 
			
		||||
                || this.mime === "application/x-javascript"
 | 
			
		||||
                || this.mime === "text/javascript");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {boolean} true if this note is HTML */
 | 
			
		||||
@@ -110,6 +160,13 @@ class Note extends Entity {
 | 
			
		||||
        return (this.type === "code" || this.type === "file" || this.type === "render") && this.mime === "text/html";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {boolean} true if the note has string content (not binary) */
 | 
			
		||||
    isStringNote() {
 | 
			
		||||
        return ["text", "code", "relation-map", "search"].includes(this.type)
 | 
			
		||||
            || this.mime.startsWith('text/')
 | 
			
		||||
            || STRING_MIME_TYPES.includes(this.mime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {string} JS script environment - either "frontend" or "backend" */
 | 
			
		||||
    getScriptEnv() {
 | 
			
		||||
        if (this.isHtml() || (this.isJavaScript() && this.mime.endsWith('env=frontend'))) {
 | 
			
		||||
@@ -394,6 +451,16 @@ class Note extends Entity {
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Based on enabled, label is either set or removed.
 | 
			
		||||
     *
 | 
			
		||||
@@ -451,24 +518,32 @@ class Note extends Entity {
 | 
			
		||||
    async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     * @return {Promise<string[]>} return list of all descendant noteIds of this note. Returning just noteIds because number of notes can be huge. Includes also this note's noteId
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    async getDescendantNoteIds() {
 | 
			
		||||
        return await sql.getColumn(`
 | 
			
		||||
            WITH RECURSIVE
 | 
			
		||||
            tree(noteId) AS (
 | 
			
		||||
                SELECT ?
 | 
			
		||||
                UNION
 | 
			
		||||
                SELECT branches.noteId FROM branches
 | 
			
		||||
                    JOIN tree ON branches.parentNoteId = tree.noteId
 | 
			
		||||
                    JOIN notes ON notes.noteId = branches.noteId
 | 
			
		||||
                WHERE notes.isDeleted = 0
 | 
			
		||||
                  AND branches.isDeleted = 0
 | 
			
		||||
            )
 | 
			
		||||
            SELECT noteId FROM tree`, [this.noteId]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Finds child notes with given attribute name and value. Only own attributes are considered, not inherited ones
 | 
			
		||||
     * Finds descendant notes with given attribute name and value. Only own attributes are considered, not inherited ones
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @param {string} [value] - attribute value
 | 
			
		||||
     * @returns {Promise<Note[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async findChildNotesWithAttribute(type, name, value) {
 | 
			
		||||
    async getDescendantNotesWithAttribute(type, name, value) {
 | 
			
		||||
        const params = [this.noteId, name];
 | 
			
		||||
        let valueCondition = "";
 | 
			
		||||
 | 
			
		||||
@@ -500,22 +575,22 @@ class Note extends Entity {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Finds notes with given label name and value. Only own labels are considered, not inherited ones
 | 
			
		||||
     * Finds descendant notes with given label name and value. Only own labels are considered, not inherited ones
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @param {string} [value] - label value
 | 
			
		||||
     * @returns {Promise<Note[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async findChildNotesWithLabel(name, value) { return await this.findChildNotesWithAttribute(LABEL, name, value); }
 | 
			
		||||
    async getDescendantNotesWithLabel(name, value) { return await this.getDescendantNotesWithAttribute(LABEL, name, value); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Finds notes with given relation name and value. Only own relations are considered, not inherited ones
 | 
			
		||||
     * Finds descendant notes with given relation name and value. Only own relations are considered, not inherited ones
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @param {string} [value] - relation value
 | 
			
		||||
     * @returns {Promise<Note[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async findChildNotesWithRelation(name, value) { return await this.findChildNotesWithAttribute(RELATION, name, value); }
 | 
			
		||||
    async getDescendantNotesWithRelation(name, value) { return await this.getDescendantNotesWithAttribute(RELATION, name, value); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns note revisions of this note.
 | 
			
		||||
@@ -608,17 +683,6 @@ class Note extends Entity {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    beforeSaving() {
 | 
			
		||||
        if (this.isJson() && this.jsonContent) {
 | 
			
		||||
            this.content = JSON.stringify(this.jsonContent, null, '\t');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // we do this here because encryption needs the note ID for the IV
 | 
			
		||||
        this.generateIdIfNecessary();
 | 
			
		||||
 | 
			
		||||
        if (this.isProtected) {
 | 
			
		||||
            protectedSessionService.encryptNote(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.isDeleted) {
 | 
			
		||||
            this.isDeleted = false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -633,6 +697,24 @@ class Note extends Entity {
 | 
			
		||||
            this.dateModified = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        if (pojo.isProtected) {
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.encryptNote(pojo);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // updating protected note outside of protected session means we will keep original ciphertexts
 | 
			
		||||
                pojo.title = pojo.titleCipherText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delete pojo.isContentAvailable;
 | 
			
		||||
        delete pojo.__attributeCache;
 | 
			
		||||
        delete pojo.titleCipherText;
 | 
			
		||||
        delete pojo.noteContent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = Note;</code></pre>
 | 
			
		||||
@@ -645,7 +727,7 @@ module.exports = Note;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										146
									
								
								docs/backend_api/entities_note_content.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								docs/backend_api/entities_note_content.js.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <title>JSDoc: Source: entities/note_content.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: entities/note_content.js</h1>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <section>
 | 
			
		||||
        <article>
 | 
			
		||||
            <pre class="prettyprint source linenums"><code>"use strict";
 | 
			
		||||
 | 
			
		||||
const Entity = require('./entity');
 | 
			
		||||
const protectedSessionService = require('../services/protected_session');
 | 
			
		||||
const repository = require('../services/repository');
 | 
			
		||||
const dateUtils = require('../services/date_utils');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This represents a Note which is a central object in the Trilium Notes project.
 | 
			
		||||
 *
 | 
			
		||||
 * @property {string} noteContentId - primary key
 | 
			
		||||
 * @property {string} noteId - reference to owning note
 | 
			
		||||
 * @property {boolean} isProtected - true if note content is protected
 | 
			
		||||
 * @property {blob} content - note content - e.g. HTML text for text notes, file payload for files
 | 
			
		||||
 * @property {string} dateCreated
 | 
			
		||||
 * @property {string} dateModified
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Entity
 | 
			
		||||
 */
 | 
			
		||||
class NoteContent extends Entity {
 | 
			
		||||
    static get entityName() {
 | 
			
		||||
        return "note_contents";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get primaryKeyName() {
 | 
			
		||||
        return "noteContentId";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get hashedProperties() {
 | 
			
		||||
        return ["noteContentId", "noteId", "isProtected", "content"];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param row - object containing database row from "note_contents" table
 | 
			
		||||
     */
 | 
			
		||||
    constructor(row) {
 | 
			
		||||
        super(row);
 | 
			
		||||
 | 
			
		||||
        this.isProtected = !!this.isProtected;
 | 
			
		||||
        /* true if content (meaning any kind of potentially encrypted content) is either not encrypted
 | 
			
		||||
         * or encrypted, but with available protected session (so effectively decrypted) */
 | 
			
		||||
        this.isContentAvailable = true;
 | 
			
		||||
 | 
			
		||||
        // check if there's noteContentId, otherwise this is a new entity which wasn't encrypted yet
 | 
			
		||||
        if (this.isProtected && this.noteContentId) {
 | 
			
		||||
            this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
 | 
			
		||||
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.decryptNoteContent(this);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // saving ciphertexts in case we do want to update protected note outside of protected session
 | 
			
		||||
                // (which is allowed)
 | 
			
		||||
                this.contentCipherText = this.content;
 | 
			
		||||
                this.content = "";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @returns {Promise<Note>}
 | 
			
		||||
     */
 | 
			
		||||
    async getNote() {
 | 
			
		||||
        return await repository.getNote(this.noteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    beforeSaving() {
 | 
			
		||||
        if (!this.dateCreated) {
 | 
			
		||||
            this.dateCreated = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.beforeSaving();
 | 
			
		||||
 | 
			
		||||
        if (this.isChanged) {
 | 
			
		||||
            this.dateModified = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        if (pojo.isProtected) {
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.encryptNoteContent(pojo);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // updating protected note outside of protected session means we will keep original ciphertext
 | 
			
		||||
                pojo.content = pojo.contentCipherText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delete pojo.isContentAvailable;
 | 
			
		||||
        delete pojo.contentCipherText;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = NoteContent;</code></pre>
 | 
			
		||||
        </article>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 | 
			
		||||
<footer>
 | 
			
		||||
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
 | 
			
		||||
</footer>
 | 
			
		||||
 | 
			
		||||
<script> prettyPrint(); </script>
 | 
			
		||||
<script src="scripts/linenumber.js"> </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -85,7 +85,7 @@ module.exports = NoteRevision;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -72,7 +72,7 @@ module.exports = Option;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ module.exports = RecentNote;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -272,7 +272,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line144">line 144</a>
 | 
			
		||||
        <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line149">line 149</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -558,7 +558,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line151">line 151</a>
 | 
			
		||||
        <a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line156">line 156</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -588,7 +588,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ const repository = require('./repository');
 | 
			
		||||
const axios = require('axios');
 | 
			
		||||
const cloningService = require('./cloning');
 | 
			
		||||
const messagingService = require('./messaging');
 | 
			
		||||
const appInfo = require('./app_info');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the main backend API interface for scripts. It's published in the local "api" object.
 | 
			
		||||
@@ -46,13 +47,17 @@ const messagingService = require('./messaging');
 | 
			
		||||
 * @constructor
 | 
			
		||||
 * @hideconstructor
 | 
			
		||||
 */
 | 
			
		||||
function BackendScriptApi(startNote, currentNote, originEntity) {
 | 
			
		||||
function BackendScriptApi(currentNote, apiParams) {
 | 
			
		||||
    /** @property {Note} note where script started executing */
 | 
			
		||||
    this.startNote = startNote;
 | 
			
		||||
    this.startNote = apiParams.startNote;
 | 
			
		||||
    /** @property {Note} note where script is currently executing */
 | 
			
		||||
    this.currentNote = currentNote;
 | 
			
		||||
    /** @property {Entity} entity whose event triggered this executions */
 | 
			
		||||
    this.originEntity = originEntity;
 | 
			
		||||
    this.originEntity = apiParams.originEntity;
 | 
			
		||||
 | 
			
		||||
    for (const key in apiParams) {
 | 
			
		||||
        this[key] = apiParams[key];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.axios = axios;
 | 
			
		||||
 | 
			
		||||
@@ -196,6 +201,23 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
 | 
			
		||||
     */
 | 
			
		||||
    this.createNote = noteService.createNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates new note according to given params and force all connected clients to refresh their tree.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} parentNoteId - create new note under this parent
 | 
			
		||||
     * @param {string} title
 | 
			
		||||
     * @param {string} [content=""]
 | 
			
		||||
     * @param {CreateNoteExtraOptions} [extraOptions={}]
 | 
			
		||||
     * @returns {Promise<{note: Note, branch: Branch}>} object contains newly created entities note and branch
 | 
			
		||||
     */
 | 
			
		||||
    this.createNoteAndRefresh = async function(parentNoteId, title, content, extraOptions) {
 | 
			
		||||
        await noteService.createNote(parentNoteId, title, content, extraOptions);
 | 
			
		||||
 | 
			
		||||
        messagingService.refreshTree();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Log given message to trilium logs.
 | 
			
		||||
     *
 | 
			
		||||
@@ -212,14 +234,42 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
 | 
			
		||||
    this.getRootCalendarNote = dateNoteService.getRootCalendarNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns day note for given date (YYYY-MM-DD format). If such note doesn't exist, it is created.
 | 
			
		||||
     * Returns day note for given date. If such note doesn't exist, it is created.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {string} date
 | 
			
		||||
     * @param {string} date in YYYY-MM-DD format
 | 
			
		||||
     * @returns {Promise<Note|null>}
 | 
			
		||||
     */
 | 
			
		||||
    this.getDateNote = dateNoteService.getDateNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns note for the first date of the week of the given date.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {string} date in YYYY-MM-DD format
 | 
			
		||||
     * @param {object} options - "startOfTheWeek" - either "monday" (default) or "sunday"
 | 
			
		||||
     * @returns {Promise<Note|null>}
 | 
			
		||||
     */
 | 
			
		||||
    this.getWeekNote = dateNoteService.getWeekNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns month note for given date. If such note doesn't exist, it is created.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {string} date in YYYY-MM format
 | 
			
		||||
     * @returns {Promise<Note|null>}
 | 
			
		||||
     */
 | 
			
		||||
    this.getMonthNote = dateNoteService.getMonthNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns year note for given year. If such note doesn't exist, it is created.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {string} year in YYYY format
 | 
			
		||||
     * @returns {Promise<Note|null>}
 | 
			
		||||
     */
 | 
			
		||||
    this.getYearNote = dateNoteService.getYearNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {string} parentNoteId - this note's child notes will be sorted
 | 
			
		||||
@@ -253,13 +303,20 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
 | 
			
		||||
     */
 | 
			
		||||
    this.transactional = sql.transactional;
 | 
			
		||||
 | 
			
		||||
    this.sql = sql;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Trigger tree refresh in all connected clients. This is required when some tree change happens in
 | 
			
		||||
     * the backend.
 | 
			
		||||
     *
 | 
			
		||||
     * @returns {Promise<void>}
 | 
			
		||||
     */
 | 
			
		||||
    this.refreshTree = () => messagingService.sendMessageToAllClients({ type: 'refresh-tree' });
 | 
			
		||||
    this.refreshTree = messagingService.refreshTree;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return {{syncVersion, appVersion, buildRevision, dbVersion, dataDirectory, buildDate}|*} - object representing basic info about running Trilium version
 | 
			
		||||
     */
 | 
			
		||||
    this.getAppInfo = () => appInfo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = BackendScriptApi;</code></pre>
 | 
			
		||||
@@ -272,7 +329,7 @@ module.exports = BackendScriptApi;</code></pre>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<nav>
 | 
			
		||||
    <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</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="ApiToken.html">ApiToken</a></li><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="Entity.html">Entity</a></li><li><a href="Link.html">Link</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteContent.html">NoteContent</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line16">line 16</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line18">line 18</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -221,7 +221,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line22">line 22</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line24">line 24</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -334,7 +334,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line24">line 24</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line26">line 26</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -444,7 +444,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line20">line 20</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line22">line 22</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -573,7 +573,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line41">line 41</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line43">line 43</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -726,7 +726,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line33">line 33</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line35">line 35</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -879,7 +879,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line60">line 60</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line62">line 62</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1057,7 +1057,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line197">line 197</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line199">line 199</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1188,7 +1188,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line157">line 157</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line159">line 159</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1244,6 +1244,214 @@
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getActiveNote"><span class="type-signature"></span>getActiveNote<span class="signature">()</span><span class="type-signature"> → {<a href="NoteFull.html">NoteFull</a>}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line211">line 211</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h5>Returns:</h5>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
<div class="param-desc">
 | 
			
		||||
    active note (loaded into right pane)
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl>
 | 
			
		||||
    <dt>
 | 
			
		||||
        Type
 | 
			
		||||
    </dt>
 | 
			
		||||
    <dd>
 | 
			
		||||
        
 | 
			
		||||
<span class="param-type"><a href="NoteFull.html">NoteFull</a></span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dd>
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getActiveNoteContent"><span class="type-signature"></span>getActiveNoteContent<span class="signature">()</span><span class="type-signature"> → {string}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line205">line 205</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h5>Returns:</h5>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
<div class="param-desc">
 | 
			
		||||
    content of active note (loaded into right pane)
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl>
 | 
			
		||||
    <dt>
 | 
			
		||||
        Type
 | 
			
		||||
    </dt>
 | 
			
		||||
    <dd>
 | 
			
		||||
        
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dd>
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getCodeMimeTypes"><span class="type-signature"></span>getCodeMimeTypes<span class="signature">()</span><span class="type-signature"> → {array}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1292,7 +1500,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line221">line 221</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line242">line 242</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1348,110 +1556,6 @@
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getCurrentNoteContent"><span class="type-signature"></span>getCurrentNoteContent<span class="signature">()</span><span class="type-signature"> → {string}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line203">line 203</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h5>Returns:</h5>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
<div class="param-desc">
 | 
			
		||||
    content of currently loaded note in the editor (HTML, code etc.)
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl>
 | 
			
		||||
    <dt>
 | 
			
		||||
        Type
 | 
			
		||||
    </dt>
 | 
			
		||||
    <dd>
 | 
			
		||||
        
 | 
			
		||||
<span class="param-type">string</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dd>
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="getDefaultCodeMimeTypes"><span class="type-signature"></span>getDefaultCodeMimeTypes<span class="signature">()</span><span class="type-signature"> → {array}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1500,7 +1604,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line215">line 215</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line236">line 236</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1609,7 +1713,7 @@ if some action needs to happen on only one specific instance.
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line150">line 150</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line152">line 152</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1808,7 +1912,7 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line142">line 142</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line144">line 144</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1860,6 +1964,117 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="isNoteStillActive"><span class="type-signature"></span>isNoteStillActive<span class="signature">()</span><span class="type-signature"> → {boolean}</span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="description">
 | 
			
		||||
    This method checks whether user navigated away from the note from which the scripts has been started.
 | 
			
		||||
This is necessary because script execution is async and by the time it is finished, the user might have
 | 
			
		||||
already navigated away from this page - the end result would be that script might return data for the wrong
 | 
			
		||||
note.
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line222">line 222</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<h5>Returns:</h5>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
<div class="param-desc">
 | 
			
		||||
    returns true if the original note is still loaded, false if user switched to another
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl>
 | 
			
		||||
    <dt>
 | 
			
		||||
        Type
 | 
			
		||||
    </dt>
 | 
			
		||||
    <dd>
 | 
			
		||||
        
 | 
			
		||||
<span class="param-type">boolean</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </dd>
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="onNoteChange"><span class="type-signature"></span>onNoteChange<span class="signature">(func)</span><span class="type-signature"></span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -1957,7 +2172,7 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line209">line 209</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line230">line 230</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2088,7 +2303,7 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line164">line 164</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line166">line 166</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2140,6 +2355,88 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="protectActiveNote"><span class="type-signature"></span>protectActiveNote<span class="signature">()</span><span class="type-signature"></span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line259">line 259</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2196,7 +2493,7 @@ otherwise (by e.g. createNoteLink())
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line188">line 188</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line190">line 190</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2373,7 +2670,7 @@ Internally this serializes the anonymous function into string and sends it to ba
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line110">line 110</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line112">line 112</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2526,7 +2823,138 @@ Internally this serializes the anonymous function into string and sends it to ba
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line227">line 227</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line248">line 248</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <h4 class="name" id="setupElementTooltip"><span class="type-signature"></span>setupElementTooltip<span class="signature">($el)</span><span class="type-signature"></span></h4>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <h5>Parameters:</h5>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
<table class="params">
 | 
			
		||||
    <thead>
 | 
			
		||||
    <tr>
 | 
			
		||||
        
 | 
			
		||||
        <th>Name</th>
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th>Type</th>
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        <th class="last">Description</th>
 | 
			
		||||
    </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
 | 
			
		||||
    <tbody>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
        <tr>
 | 
			
		||||
            
 | 
			
		||||
                <td class="name"><code>$el</code></td>
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="type">
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
<span class="param-type">object</span>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
            </td>
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            <td class="description last">jquery object on which to setup the tooltip</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    </tbody>
 | 
			
		||||
</table>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line254">line 254</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2661,7 +3089,7 @@ Internally this serializes the anonymous function into string and sends it to ba
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line180">line 180</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line182">line 182</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@@ -2796,7 +3224,7 @@ Internally this serializes the anonymous function into string and sends it to ba
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line172">line 172</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line174">line 174</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -141,7 +141,123 @@
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
<h4 class="name" id="content"><span class="type-signature"></span>content<span class="type-signature"></span></h4>
 | 
			
		||||
<h4 class="name" id="dateCreated"><span class="type-signature"></span>dateCreated<span class="type-signature"></span></h4>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="entities_note_full.js.html">entities/note_full.js</a>, <a href="entities_note_full.js.html#line14">line 14</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
<h4 class="name" id="dateModified"><span class="type-signature"></span>dateModified<span class="type-signature"></span></h4>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="entities_note_full.js.html">entities/note_full.js</a>, <a href="entities_note_full.js.html#line17">line 17</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
            
 | 
			
		||||
<h4 class="name" id="noteContent"><span class="type-signature"></span>noteContent<span class="type-signature"></span></h4>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -199,64 +315,6 @@
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
<h4 class="name" id="jsonContent"><span class="type-signature"></span>jsonContent<span class="type-signature"></span></h4>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<dl class="details">
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="entities_note_full.js.html">entities/note_full.js</a>, <a href="entities_note_full.js.html#line16">line 16</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
</dl>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										86
									
								
								docs/frontend_api/entities_attribute.js.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								docs/frontend_api/entities_attribute.js.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="utf-8">
 | 
			
		||||
    <title>JSDoc: Source: entities/attribute.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: entities/attribute.js</h1>
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    <section>
 | 
			
		||||
        <article>
 | 
			
		||||
            <pre class="prettyprint source linenums"><code>class Attribute {
 | 
			
		||||
    constructor(treeCache, row) {
 | 
			
		||||
        this.treeCache = treeCache;
 | 
			
		||||
        /** @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;
 | 
			
		||||
        /** @param {boolean} isDeleted */
 | 
			
		||||
        this.isDeleted = row.isDeleted;
 | 
			
		||||
        /** @param {string} dateCreated */
 | 
			
		||||
        this.dateCreated = row.dateCreated;
 | 
			
		||||
        /** @param {string} dateModified */
 | 
			
		||||
        this.dateModified = row.dateModified;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {NoteShort} */
 | 
			
		||||
    async getNote() {
 | 
			
		||||
        return await this.treeCache.getNote(this.noteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get toString() {
 | 
			
		||||
        return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Attribute;</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="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<br class="clear">
 | 
			
		||||
 | 
			
		||||
<footer>
 | 
			
		||||
    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
 | 
			
		||||
</footer>
 | 
			
		||||
 | 
			
		||||
<script> prettyPrint(); </script>
 | 
			
		||||
<script src="scripts/linenumber.js"> </script>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -42,7 +42,7 @@ class Branch {
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.prefix = row.prefix;
 | 
			
		||||
        /** @param {boolean} */
 | 
			
		||||
        this.isExpanded = row.isExpanded;
 | 
			
		||||
        this.isExpanded = !!row.isExpanded;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {NoteShort} */
 | 
			
		||||
 
 | 
			
		||||
@@ -36,15 +36,13 @@ class NoteFull extends NoteShort {
 | 
			
		||||
        super(treeCache, row);
 | 
			
		||||
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.content = row.content;
 | 
			
		||||
        this.noteContent = row.noteContent;
 | 
			
		||||
 | 
			
		||||
        if (this.content !== "" && this.isJson()) {
 | 
			
		||||
            try {
 | 
			
		||||
                /** @param {object} */
 | 
			
		||||
                this.jsonContent = JSON.parse(this.content);
 | 
			
		||||
            }
 | 
			
		||||
            catch(e) {}
 | 
			
		||||
        }
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.dateCreated = row.dateCreated;
 | 
			
		||||
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.dateModified = row.dateModified;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,14 @@
 | 
			
		||||
    
 | 
			
		||||
    <section>
 | 
			
		||||
        <article>
 | 
			
		||||
            <pre class="prettyprint source linenums"><code>/**
 | 
			
		||||
            <pre class="prettyprint source linenums"><code>import server from '../services/server.js';
 | 
			
		||||
 | 
			
		||||
const LABEL = 'label';
 | 
			
		||||
const LABEL_DEFINITION = 'label-definition';
 | 
			
		||||
const RELATION = 'relation';
 | 
			
		||||
const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This note's representation is used in note tree and is kept in TreeCache.
 | 
			
		||||
 * Its notable omission is the note content.
 | 
			
		||||
 */
 | 
			
		||||
@@ -99,6 +106,140 @@ class NoteShort {
 | 
			
		||||
        return await this.treeCache.getNotes(this.getChildNoteIds());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - attribute name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async getAttributes(name) {
 | 
			
		||||
        if (!this.attributeCache) {
 | 
			
		||||
            this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (name) {
 | 
			
		||||
            return this.attributeCache.filter(attr => attr.name === name);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return this.attributeCache;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - label name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getLabels(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - label name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getLabelDefinitions(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - relation name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getRelations(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - relation name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationDefinitions(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasAttribute(type, name) {
 | 
			
		||||
        return !!await this.getAttribute(type, name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is  returned. Returns null if there's no such attribute belonging to this note.
 | 
			
		||||
     */
 | 
			
		||||
    async getAttribute(type, name) {
 | 
			
		||||
        const attributes = await this.getAttributes();
 | 
			
		||||
 | 
			
		||||
        return attributes.find(attr => attr.type === type && attr.name === name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
 | 
			
		||||
     */
 | 
			
		||||
    async getAttributeValue(type, name) {
 | 
			
		||||
        const attr = await this.getAttribute(type, name);
 | 
			
		||||
 | 
			
		||||
        return attr ? attr.value : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<boolean>} true if label exists (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<boolean>} true if relation exists (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<Attribute>} label if it exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getLabel(name) { return await this.getAttribute(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<Attribute>} relation if it exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getRelation(name) { return await this.getAttribute(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<string>} label value if label exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<string>} relation value if relation exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear note's attributes cache to force fresh reload for next attribute request.
 | 
			
		||||
     * Cache is note instance scoped.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateAttributeCache() {
 | 
			
		||||
        this.attributeCache = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get toString() {
 | 
			
		||||
        return `Note(noteId=${this.noteId}, title=${this.title})`;
 | 
			
		||||
    }
 | 
			
		||||
@@ -107,6 +248,7 @@ class NoteShort {
 | 
			
		||||
        const dto = Object.assign({}, this);
 | 
			
		||||
        delete dto.treeCache;
 | 
			
		||||
        delete dto.archived;
 | 
			
		||||
        delete dto.attributeCache;
 | 
			
		||||
 | 
			
		||||
        return dto;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -303,7 +303,7 @@
 | 
			
		||||
    
 | 
			
		||||
    <dt class="tag-source">Source:</dt>
 | 
			
		||||
    <dd class="tag-source"><ul class="dummy"><li>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line47">line 47</a>
 | 
			
		||||
        <a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line49">line 49</a>
 | 
			
		||||
    </li></ul></dd>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,8 @@ import linkService from './link.js';
 | 
			
		||||
import treeCache from './tree_cache.js';
 | 
			
		||||
import noteDetailService from './note_detail.js';
 | 
			
		||||
import noteTypeService from './note_type.js';
 | 
			
		||||
import noteTooltipService from './note_tooltip.js';
 | 
			
		||||
import protectedSessionService from'./protected_session.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the main frontend API interface for scripts. It's published in the local "api" object.
 | 
			
		||||
@@ -69,7 +71,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
    this.activateNewNote = async notePath => {
 | 
			
		||||
        await treeService.reload();
 | 
			
		||||
 | 
			
		||||
        await treeService.activateNote(notePath, true);
 | 
			
		||||
        await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -226,9 +228,28 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @returns {string} content of currently loaded note in the editor (HTML, code etc.)
 | 
			
		||||
     * @returns {string} content of active note (loaded into right pane)
 | 
			
		||||
     */
 | 
			
		||||
    this.getCurrentNoteContent = noteDetailService.getCurrentNoteContent;
 | 
			
		||||
    this.getActiveNoteContent = noteDetailService.getCurrentNoteContent;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @returns {NoteFull} active note (loaded into right pane)
 | 
			
		||||
     */
 | 
			
		||||
    this.getActiveNote = noteDetailService.getCurrentNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method checks whether user navigated away from the note from which the scripts has been started.
 | 
			
		||||
     * This is necessary because script execution is async and by the time it is finished, the user might have
 | 
			
		||||
     * already navigated away from this page - the end result would be that script might return data for the wrong
 | 
			
		||||
     * note.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @return {boolean} returns true if the original note is still loaded, false if user switched to another
 | 
			
		||||
     */
 | 
			
		||||
    this.isNoteStillActive = () => {
 | 
			
		||||
        return this.originEntity.noteId === noteDetailService.getCurrentNoteId();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
@@ -253,6 +274,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
     * @param {array} types - list of mime types to be used
 | 
			
		||||
     */
 | 
			
		||||
    this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {object} $el - jquery object on which to setup the tooltip
 | 
			
		||||
     */
 | 
			
		||||
    this.setupElementTooltip = noteTooltipService.setupElementTooltip;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     */
 | 
			
		||||
    this.protectActiveNote = protectedSessionService.protectNoteAndSendToServer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default FrontendScriptApi;</code></pre>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								electron.js
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								electron.js
									
									
									
									
									
								
							@@ -7,6 +7,7 @@ const cls = require('./src/services/cls');
 | 
			
		||||
const url = require("url");
 | 
			
		||||
const port = require('./src/services/port');
 | 
			
		||||
const appIconService = require('./src/services/app_icon');
 | 
			
		||||
const windowStateKeeper = require('electron-window-state');
 | 
			
		||||
 | 
			
		||||
const app = electron.app;
 | 
			
		||||
const globalShortcut = electron.globalShortcut;
 | 
			
		||||
@@ -28,14 +29,23 @@ function onClosed() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function createMainWindow() {
 | 
			
		||||
    let mainWindowState = windowStateKeeper({
 | 
			
		||||
        // default window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
 | 
			
		||||
        defaultWidth: 1200,
 | 
			
		||||
        defaultHeight: 800
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const win = new electron.BrowserWindow({
 | 
			
		||||
        // initial window width & height so it's usable on 1600 * 900 display (including some extra panels etc.)
 | 
			
		||||
        width: 1200,
 | 
			
		||||
        height: 800,
 | 
			
		||||
        x: mainWindowState.x,
 | 
			
		||||
        y: mainWindowState.y,
 | 
			
		||||
        width: mainWindowState.width,
 | 
			
		||||
        height: mainWindowState.height,
 | 
			
		||||
        title: 'Trilium Notes',
 | 
			
		||||
        icon: path.join(__dirname, 'src/public/images/app-icons/png/256x256.png')
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    mainWindowState.manage(win);
 | 
			
		||||
 | 
			
		||||
    win.setMenu(null);
 | 
			
		||||
    win.loadURL('http://localhost:' + await port);
 | 
			
		||||
    win.on('closed', onClosed);
 | 
			
		||||
@@ -81,7 +91,7 @@ app.on('ready', async () => {
 | 
			
		||||
        const dateNoteService = require('./src/services/date_notes');
 | 
			
		||||
        const dateUtils = require('./src/services/date_utils');
 | 
			
		||||
 | 
			
		||||
        const parentNote = await dateNoteService.getDateNote(dateUtils.nowDate());
 | 
			
		||||
        const parentNote = await dateNoteService.getDateNote(dateUtils.nowLocalDate());
 | 
			
		||||
 | 
			
		||||
        // window may be hidden / not in focus
 | 
			
		||||
        mainWindow.focus();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								issue_template.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								issue_template.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
For bug reports, please mention **version of the application** and 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
 | 
			
		||||
* `/Users/[user]/Library/Application Support/trilium-data/log` for Mac OS
 | 
			
		||||
							
								
								
									
										6866
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6866
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										57
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								package.json
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
  "name": "trilium",
 | 
			
		||||
  "productName": "Trilium Notes",
 | 
			
		||||
  "description": "Trilium Notes",
 | 
			
		||||
  "version": "0.25.2",
 | 
			
		||||
  "version": "0.30.8",
 | 
			
		||||
  "license": "AGPL-3.0-only",
 | 
			
		||||
  "main": "electron.js",
 | 
			
		||||
  "bin": {
 | 
			
		||||
@@ -17,7 +17,8 @@
 | 
			
		||||
    "start-electron": "electron . --disable-gpu",
 | 
			
		||||
    "build-backend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
 | 
			
		||||
    "build-frontend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
 | 
			
		||||
    "build-docs": "npm run build-backend-docs && npm run build-frontend-docs"
 | 
			
		||||
    "build-docs": "npm run build-backend-docs && npm run build-frontend-docs",
 | 
			
		||||
    "postinstall": "electron-builder install-app-deps"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "async-mutex": "0.1.3",
 | 
			
		||||
@@ -25,55 +26,59 @@
 | 
			
		||||
    "body-parser": "1.18.3",
 | 
			
		||||
    "cls-hooked": "4.2.2",
 | 
			
		||||
    "commonmark": "0.28.1",
 | 
			
		||||
    "cookie-parser": "1.4.3",
 | 
			
		||||
    "debug": "4.1.0",
 | 
			
		||||
    "cookie-parser": "1.4.4",
 | 
			
		||||
    "debug": "4.1.1",
 | 
			
		||||
    "ejs": "2.6.1",
 | 
			
		||||
    "electron-debug": "2.0.0",
 | 
			
		||||
    "electron-dl": "1.12.0",
 | 
			
		||||
    "electron-debug": "2.1.0",
 | 
			
		||||
    "electron-dl": "1.13.0",
 | 
			
		||||
    "electron-in-page-search": "1.3.2",
 | 
			
		||||
    "electron-window-state": "^5.0.3",
 | 
			
		||||
    "express": "4.16.4",
 | 
			
		||||
    "express-session": "1.15.6",
 | 
			
		||||
    "file-type": "10.8.0",
 | 
			
		||||
    "fs-extra": "7.0.1",
 | 
			
		||||
    "get-port": "4.0.0",
 | 
			
		||||
    "helmet": "3.15.0",
 | 
			
		||||
    "get-port": "4.2.0",
 | 
			
		||||
    "helmet": "3.15.1",
 | 
			
		||||
    "html": "1.0.0",
 | 
			
		||||
    "image-type": "3.0.0",
 | 
			
		||||
    "imagemin": "6.0.0",
 | 
			
		||||
    "imagemin": "6.1.0",
 | 
			
		||||
    "imagemin-giflossy": "5.1.10",
 | 
			
		||||
    "imagemin-mozjpeg": "8.0.0",
 | 
			
		||||
    "imagemin-pngquant": "6.0.0",
 | 
			
		||||
    "imagemin-pngquant": "7.0.0",
 | 
			
		||||
    "ini": "1.3.5",
 | 
			
		||||
    "jimp": "0.6.0",
 | 
			
		||||
    "mime-types": "^2.1.21",
 | 
			
		||||
    "moment": "2.22.2",
 | 
			
		||||
    "mime-types": "^2.1.22",
 | 
			
		||||
    "moment": "2.24.0",
 | 
			
		||||
    "multer": "1.4.1",
 | 
			
		||||
    "node-abi": "2.7.1",
 | 
			
		||||
    "open": "0.0.5",
 | 
			
		||||
    "rand-token": "0.4.0",
 | 
			
		||||
    "rcedit": "1.1.1",
 | 
			
		||||
    "request": "2.88.0",
 | 
			
		||||
    "request-promise": "4.2.2",
 | 
			
		||||
    "rimraf": "2.6.2",
 | 
			
		||||
    "rimraf": "2.6.3",
 | 
			
		||||
    "sanitize-filename": "1.6.1",
 | 
			
		||||
    "sax": "^1.2.4",
 | 
			
		||||
    "semver": "^5.6.0",
 | 
			
		||||
    "serve-favicon": "2.5.0",
 | 
			
		||||
    "session-file-store": "1.2.0",
 | 
			
		||||
    "simple-node-logger": "0.93.40",
 | 
			
		||||
    "sqlite": "3.0.0",
 | 
			
		||||
    "tar-stream": "1.6.2",
 | 
			
		||||
    "turndown": "5.0.1",
 | 
			
		||||
    "simple-node-logger": "18.12.22",
 | 
			
		||||
    "sqlite": "3.0.2",
 | 
			
		||||
    "tar-stream": "2.0.1",
 | 
			
		||||
    "turndown": "5.0.3",
 | 
			
		||||
    "unescape": "1.0.1",
 | 
			
		||||
    "ws": "6.1.2",
 | 
			
		||||
    "ws": "6.1.4",
 | 
			
		||||
    "xml2js": "0.4.19"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "devtron": "1.4.0",
 | 
			
		||||
    "electron": "4.0.0-beta.8",
 | 
			
		||||
    "electron-compile": "6.4.3",
 | 
			
		||||
    "electron-packager": "12.2.0",
 | 
			
		||||
    "electron-rebuild": "1.8.2",
 | 
			
		||||
    "electron": "4.0.3",
 | 
			
		||||
    "electron-builder": "20.38.5",
 | 
			
		||||
    "electron-compile": "6.4.4",
 | 
			
		||||
    "electron-installer-debian": "^1.1.1",
 | 
			
		||||
    "electron-packager": "13.1.0",
 | 
			
		||||
    "electron-rebuild": "1.8.4",
 | 
			
		||||
    "lorem-ipsum": "1.0.6",
 | 
			
		||||
    "tape": "4.9.1",
 | 
			
		||||
    "xo": "0.23.0"
 | 
			
		||||
    "tape": "4.10.1",
 | 
			
		||||
    "xo": "0.24.0"
 | 
			
		||||
  },
 | 
			
		||||
  "xo": {
 | 
			
		||||
    "envs": [
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ app.use((req, res, next) => {
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.use(bodyParser.json({limit: '50mb'}));
 | 
			
		||||
app.use(bodyParser.json({limit: '500mb'}));
 | 
			
		||||
app.use(bodyParser.urlencoded({extended: false}));
 | 
			
		||||
app.use(cookieParser());
 | 
			
		||||
app.use(express.static(path.join(__dirname, 'public')));
 | 
			
		||||
@@ -63,6 +63,8 @@ app.use(favicon(__dirname + '/public/images/app-icons/win/icon.ico'));
 | 
			
		||||
 | 
			
		||||
require('./routes/routes').register(app);
 | 
			
		||||
 | 
			
		||||
require('./routes/custom').register(app);
 | 
			
		||||
 | 
			
		||||
// catch 404 and forward to error handler
 | 
			
		||||
app.use((req, res, next) => {
 | 
			
		||||
    const err = new Error('Router not found for request ' + req.url);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,11 @@ class Entity {
 | 
			
		||||
     */
 | 
			
		||||
    constructor(row = {}) {
 | 
			
		||||
        for (const key in row) {
 | 
			
		||||
            // ! is used when joint-fetching notes and note_contents objects for performance
 | 
			
		||||
            if (!key.startsWith('!')) {
 | 
			
		||||
                this[key] = row[key];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ('isDeleted' in this) {
 | 
			
		||||
            this.isDeleted = !!this.isDeleted;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
const Note = require('../entities/note');
 | 
			
		||||
const NoteContent = require('../entities/note_content');
 | 
			
		||||
const NoteRevision = require('../entities/note_revision');
 | 
			
		||||
const Link = require('../entities/link');
 | 
			
		||||
const Branch = require('../entities/branch');
 | 
			
		||||
@@ -12,10 +13,12 @@ const ENTITY_NAME_TO_ENTITY = {
 | 
			
		||||
    "attributes": Attribute,
 | 
			
		||||
    "branches": Branch,
 | 
			
		||||
    "notes": Note,
 | 
			
		||||
    "note_contents": NoteContent,
 | 
			
		||||
    "note_revisions": NoteRevision,
 | 
			
		||||
    "recent_notes": RecentNote,
 | 
			
		||||
    "options": Option,
 | 
			
		||||
    "api_tokens": ApiToken
 | 
			
		||||
    "api_tokens": ApiToken,
 | 
			
		||||
    "links": Link
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function getEntityFromEntityName(entityName) {
 | 
			
		||||
@@ -47,6 +50,9 @@ function createEntityFromRow(row) {
 | 
			
		||||
    else if (row.branchId) {
 | 
			
		||||
        entity = new Branch(row);
 | 
			
		||||
    }
 | 
			
		||||
    else if (row.noteContentId) {
 | 
			
		||||
        entity = new NoteContent(row);
 | 
			
		||||
    }
 | 
			
		||||
    else if (row.noteId) {
 | 
			
		||||
        entity = new Note(row);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
const Entity = require('./entity');
 | 
			
		||||
const Attribute = require('./attribute');
 | 
			
		||||
const NoteContent = require('./note_content');
 | 
			
		||||
const protectedSessionService = require('../services/protected_session');
 | 
			
		||||
const repository = require('../services/repository');
 | 
			
		||||
const sql = require('../services/sql');
 | 
			
		||||
@@ -12,6 +13,8 @@ const LABEL_DEFINITION = 'label-definition';
 | 
			
		||||
const RELATION = 'relation';
 | 
			
		||||
const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 | 
			
		||||
const STRING_MIME_TYPES = ["application/x-javascript"];
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This represents a Note which is a central object in the Trilium Notes project.
 | 
			
		||||
 *
 | 
			
		||||
@@ -19,7 +22,6 @@ const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 * @property {string} type - one of "text", "code", "file" or "render"
 | 
			
		||||
 * @property {string} mime - MIME type, e.g. "text/html"
 | 
			
		||||
 * @property {string} title - note title
 | 
			
		||||
 * @property {string} content - note content - e.g. HTML text for text notes, file payload for files
 | 
			
		||||
 * @property {boolean} isProtected - true if note is protected
 | 
			
		||||
 * @property {boolean} isDeleted - true if note is deleted
 | 
			
		||||
 * @property {string} dateCreated
 | 
			
		||||
@@ -30,7 +32,7 @@ const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
class Note extends Entity {
 | 
			
		||||
    static get entityName() { return "notes"; }
 | 
			
		||||
    static get primaryKeyName() { return "noteId"; }
 | 
			
		||||
    static get hashedProperties() { return ["noteId", "title", "content", "type", "isProtected", "isDeleted"]; }
 | 
			
		||||
    static get hashedProperties() { return ["noteId", "title", "type", "isProtected", "isDeleted"]; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param row - object containing database row from "notes" table
 | 
			
		||||
@@ -47,19 +49,64 @@ class Note extends Entity {
 | 
			
		||||
        if (this.isProtected && this.noteId) {
 | 
			
		||||
            this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
 | 
			
		||||
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.decryptNote(this);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        this.setContent(this.content);
 | 
			
		||||
            else {
 | 
			
		||||
                // saving ciphertexts in case we do want to update protected note outside of protected session
 | 
			
		||||
                // (which is allowed)
 | 
			
		||||
                this.titleCipherText = this.title;
 | 
			
		||||
                this.title = "[protected]";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    setContent(content) {
 | 
			
		||||
        this.content = content;
 | 
			
		||||
    /** @returns {Promise<NoteContent>} */
 | 
			
		||||
    async getNoteContent() {
 | 
			
		||||
        if (!this.noteContent) {
 | 
			
		||||
            this.noteContent = await repository.getEntity(`SELECT * FROM note_contents WHERE noteId = ?`, [this.noteId]);
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            this.jsonContent = JSON.parse(this.content);
 | 
			
		||||
            if (!this.noteContent) {
 | 
			
		||||
                throw new Error("Note content not found for noteId=" + this.noteId);
 | 
			
		||||
            }
 | 
			
		||||
        catch(e) {}
 | 
			
		||||
 | 
			
		||||
            if (this.isStringNote()) {
 | 
			
		||||
                this.noteContent.content = this.noteContent.content.toString("UTF-8");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.noteContent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise<*>} */
 | 
			
		||||
    async getContent() {
 | 
			
		||||
        const noteContent = await this.getNoteContent();
 | 
			
		||||
 | 
			
		||||
        return noteContent.content;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise<*>} */
 | 
			
		||||
    async getJsonContent() {
 | 
			
		||||
        const content = await this.getContent();
 | 
			
		||||
 | 
			
		||||
        return JSON.parse(content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise} */
 | 
			
		||||
    async setContent(content) {
 | 
			
		||||
        if (!this.noteContent) {
 | 
			
		||||
            // make sure it is loaded
 | 
			
		||||
            await this.getNoteContent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.noteContent.content = content;
 | 
			
		||||
 | 
			
		||||
        await this.noteContent.save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {Promise} */
 | 
			
		||||
    async setJsonContent(content) {
 | 
			
		||||
        await this.setContent(JSON.stringify(content, null, '\t'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {boolean} true if this note is the root of the note tree. Root note has "root" noteId */
 | 
			
		||||
@@ -85,6 +132,13 @@ class Note extends Entity {
 | 
			
		||||
        return (this.type === "code" || this.type === "file" || this.type === "render") && this.mime === "text/html";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {boolean} true if the note has string content (not binary) */
 | 
			
		||||
    isStringNote() {
 | 
			
		||||
        return ["text", "code", "relation-map", "search"].includes(this.type)
 | 
			
		||||
            || this.mime.startsWith('text/')
 | 
			
		||||
            || STRING_MIME_TYPES.includes(this.mime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {string} JS script environment - either "frontend" or "backend" */
 | 
			
		||||
    getScriptEnv() {
 | 
			
		||||
        if (this.isHtml() || (this.isJavaScript() && this.mime.endsWith('env=frontend'))) {
 | 
			
		||||
@@ -369,6 +423,16 @@ class Note extends Entity {
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Based on enabled, label is either set or removed.
 | 
			
		||||
     *
 | 
			
		||||
@@ -425,16 +489,6 @@ class Note extends Entity {
 | 
			
		||||
     */
 | 
			
		||||
    async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return {Promise<string[]>} return list of all descendant noteIds of this note. Returning just noteIds because number of notes can be huge. Includes also this note's noteId
 | 
			
		||||
     */
 | 
			
		||||
@@ -601,13 +655,6 @@ class Note extends Entity {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    beforeSaving() {
 | 
			
		||||
        if (this.isJson() && this.jsonContent) {
 | 
			
		||||
            this.content = JSON.stringify(this.jsonContent, null, '\t');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // we do this here because encryption needs the note ID for the IV
 | 
			
		||||
        this.generateIdIfNecessary();
 | 
			
		||||
 | 
			
		||||
        if (!this.isDeleted) {
 | 
			
		||||
            this.isDeleted = false;
 | 
			
		||||
        }
 | 
			
		||||
@@ -626,12 +673,19 @@ class Note extends Entity {
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        if (pojo.isProtected) {
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.encryptNote(pojo);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // updating protected note outside of protected session means we will keep original ciphertexts
 | 
			
		||||
                pojo.title = pojo.titleCipherText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delete pojo.jsonContent;
 | 
			
		||||
        delete pojo.isContentAvailable;
 | 
			
		||||
        delete pojo.__attributeCache;
 | 
			
		||||
        delete pojo.titleCipherText;
 | 
			
		||||
        delete pojo.noteContent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										96
									
								
								src/entities/note_content.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/entities/note_content.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
const Entity = require('./entity');
 | 
			
		||||
const protectedSessionService = require('../services/protected_session');
 | 
			
		||||
const repository = require('../services/repository');
 | 
			
		||||
const dateUtils = require('../services/date_utils');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This represents a Note which is a central object in the Trilium Notes project.
 | 
			
		||||
 *
 | 
			
		||||
 * @property {string} noteContentId - primary key
 | 
			
		||||
 * @property {string} noteId - reference to owning note
 | 
			
		||||
 * @property {boolean} isProtected - true if note content is protected
 | 
			
		||||
 * @property {blob} content - note content - e.g. HTML text for text notes, file payload for files
 | 
			
		||||
 * @property {string} dateCreated
 | 
			
		||||
 * @property {string} dateModified
 | 
			
		||||
 *
 | 
			
		||||
 * @extends Entity
 | 
			
		||||
 */
 | 
			
		||||
class NoteContent extends Entity {
 | 
			
		||||
    static get entityName() {
 | 
			
		||||
        return "note_contents";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get primaryKeyName() {
 | 
			
		||||
        return "noteContentId";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get hashedProperties() {
 | 
			
		||||
        return ["noteContentId", "noteId", "isProtected", "content"];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param row - object containing database row from "note_contents" table
 | 
			
		||||
     */
 | 
			
		||||
    constructor(row) {
 | 
			
		||||
        super(row);
 | 
			
		||||
 | 
			
		||||
        this.isProtected = !!this.isProtected;
 | 
			
		||||
        /* true if content (meaning any kind of potentially encrypted content) is either not encrypted
 | 
			
		||||
         * or encrypted, but with available protected session (so effectively decrypted) */
 | 
			
		||||
        this.isContentAvailable = true;
 | 
			
		||||
 | 
			
		||||
        // check if there's noteContentId, otherwise this is a new entity which wasn't encrypted yet
 | 
			
		||||
        if (this.isProtected && this.noteContentId) {
 | 
			
		||||
            this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
 | 
			
		||||
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.decryptNoteContent(this);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // saving ciphertexts in case we do want to update protected note outside of protected session
 | 
			
		||||
                // (which is allowed)
 | 
			
		||||
                this.contentCipherText = this.content;
 | 
			
		||||
                this.content = "";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @returns {Promise<Note>}
 | 
			
		||||
     */
 | 
			
		||||
    async getNote() {
 | 
			
		||||
        return await repository.getNote(this.noteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    beforeSaving() {
 | 
			
		||||
        if (!this.dateCreated) {
 | 
			
		||||
            this.dateCreated = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.beforeSaving();
 | 
			
		||||
 | 
			
		||||
        if (this.isChanged) {
 | 
			
		||||
            this.dateModified = dateUtils.nowDate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // cannot be static!
 | 
			
		||||
    updatePojo(pojo) {
 | 
			
		||||
        if (pojo.isProtected) {
 | 
			
		||||
            if (this.isContentAvailable) {
 | 
			
		||||
                protectedSessionService.encryptNoteContent(pojo);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // updating protected note outside of protected session means we will keep original ciphertext
 | 
			
		||||
                pojo.content = pojo.contentCipherText;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        delete pojo.isContentAvailable;
 | 
			
		||||
        delete pojo.contentCipherText;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = NoteContent;
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/public/images/app-icons/ios/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/public/images/app-icons/ios/apple-touch-icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.4 KiB  | 
@@ -1 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#fafafa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shield"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000000" stroke-opacity="0.03" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shield"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 296 B  | 
							
								
								
									
										163
									
								
								src/public/javascripts/desktop.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								src/public/javascripts/desktop.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,163 @@
 | 
			
		||||
import addLinkDialog from './dialogs/add_link.js';
 | 
			
		||||
import jumpToNoteDialog from './dialogs/jump_to_note.js';
 | 
			
		||||
import attributesDialog from './dialogs/attributes.js';
 | 
			
		||||
import noteRevisionsDialog from './dialogs/note_revisions.js';
 | 
			
		||||
import noteSourceDialog from './dialogs/note_source.js';
 | 
			
		||||
import recentChangesDialog from './dialogs/recent_changes.js';
 | 
			
		||||
import optionsDialog from './dialogs/options.js';
 | 
			
		||||
import sqlConsoleDialog from './dialogs/sql_console.js';
 | 
			
		||||
import markdownImportDialog from './dialogs/markdown_import.js';
 | 
			
		||||
import exportDialog from './dialogs/export.js';
 | 
			
		||||
import importDialog from './dialogs/import.js';
 | 
			
		||||
 | 
			
		||||
import cloning from './services/cloning.js';
 | 
			
		||||
import contextMenu from './services/tree_context_menu.js';
 | 
			
		||||
import dragAndDropSetup from './services/drag_and_drop.js';
 | 
			
		||||
import link from './services/link.js';
 | 
			
		||||
import messagingService from './services/messaging.js';
 | 
			
		||||
import noteDetailService from './services/note_detail.js';
 | 
			
		||||
import noteType from './services/note_type.js';
 | 
			
		||||
import protectedSessionService from './services/protected_session.js';
 | 
			
		||||
import protectedSessionHolder from './services/protected_session_holder.js';
 | 
			
		||||
import searchNotesService from './services/search_notes.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 treeChanges from './services/branches.js';
 | 
			
		||||
import treeUtils from './services/tree_utils.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 './services/note_type.js';
 | 
			
		||||
import linkService from './services/link.js';
 | 
			
		||||
import noteAutocompleteService from './services/note_autocomplete.js';
 | 
			
		||||
import macInit from './services/mac_init.js';
 | 
			
		||||
import cssLoader from './services/css_loader.js';
 | 
			
		||||
 | 
			
		||||
// required for CKEditor image upload plugin
 | 
			
		||||
window.glob.getCurrentNode = treeService.getCurrentNode;
 | 
			
		||||
window.glob.getHeaders = server.getHeaders;
 | 
			
		||||
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
 | 
			
		||||
// this is required by CKEditor when uploading images
 | 
			
		||||
window.glob.noteChanged = noteDetailService.noteChanged;
 | 
			
		||||
window.glob.refreshTree = treeService.reload;
 | 
			
		||||
 | 
			
		||||
// required for ESLint plugin
 | 
			
		||||
window.glob.getCurrentNote = noteDetailService.getCurrentNote;
 | 
			
		||||
window.glob.requireLibrary = libraryLoader.requireLibrary;
 | 
			
		||||
window.glob.ESLINT = libraryLoader.ESLINT;
 | 
			
		||||
 | 
			
		||||
protectedSessionHolder.setProtectedSessionId(null);
 | 
			
		||||
 | 
			
		||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
 | 
			
		||||
    const string = msg.toLowerCase();
 | 
			
		||||
 | 
			
		||||
    let message = "Uncaught error: ";
 | 
			
		||||
 | 
			
		||||
    if (string.includes("Cannot read property 'defaultView' of undefined")) {
 | 
			
		||||
        // ignore this specific error which is very common but we don't know where it comes from
 | 
			
		||||
        // and it seems to be harmless
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (string.includes("script error")) {
 | 
			
		||||
        message += 'No details available';
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        message += [
 | 
			
		||||
            'Message: ' + msg,
 | 
			
		||||
            'URL: ' + url,
 | 
			
		||||
            'Line: ' + lineNo,
 | 
			
		||||
            'Column: ' + columnNo,
 | 
			
		||||
            'Error object: ' + JSON.stringify(error)
 | 
			
		||||
        ].join(' - ');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    messagingService.logError(message);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
for (const appCssNoteId of window.appCssNoteIds) {
 | 
			
		||||
    cssLoader.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');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#logout-button").toggle(!utils.isElectron());
 | 
			
		||||
 | 
			
		||||
$("#logout-button").click(() => {
 | 
			
		||||
    const $logoutForm = $('<form action="logout" method="POST">');
 | 
			
		||||
 | 
			
		||||
    $("body").append($logoutForm);
 | 
			
		||||
    $logoutForm.submit();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#tree").on("click", ".unhoist-button", hoistedNoteService.unhoist);
 | 
			
		||||
 | 
			
		||||
$("body").on("click", "a.external", function () {
 | 
			
		||||
    window.open($(this).attr("href"), '_blank');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
if (utils.isElectron()) {
 | 
			
		||||
    require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
 | 
			
		||||
        // this might occur when day note had to be created
 | 
			
		||||
        if (!await treeCache.getNote(parentNoteId)) {
 | 
			
		||||
            await treeService.reload();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await treeService.activateNote(parentNoteId);
 | 
			
		||||
 | 
			
		||||
        setTimeout(async () => {
 | 
			
		||||
            const parentNode = treeService.getCurrentNode();
 | 
			
		||||
 | 
			
		||||
            const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', parentNode.data.isProtected);
 | 
			
		||||
 | 
			
		||||
            await treeService.activateNote(note.noteId);
 | 
			
		||||
 | 
			
		||||
        }, 500);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$("#export-note-button").click(function () {
 | 
			
		||||
    if ($(this).hasClass("disabled")) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exportDialog.showDialog('single');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$('[data-toggle="tooltip"]').tooltip({
 | 
			
		||||
    html: true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#import-files-button").click(importDialog.showDialog);
 | 
			
		||||
 | 
			
		||||
macInit.init();
 | 
			
		||||
 | 
			
		||||
searchNotesService.init(); // should be in front of treeService since that one manipulates address bar hash
 | 
			
		||||
 | 
			
		||||
treeService.showTree();
 | 
			
		||||
 | 
			
		||||
entrypoints.registerEntrypoints();
 | 
			
		||||
 | 
			
		||||
noteTooltipService.setupGlobalTooltip();
 | 
			
		||||
 | 
			
		||||
bundle.executeStartupBundles();
 | 
			
		||||
 | 
			
		||||
noteTypeService.init();
 | 
			
		||||
 | 
			
		||||
linkService.init();
 | 
			
		||||
 | 
			
		||||
noteAutocompleteService.init();
 | 
			
		||||
@@ -137,6 +137,10 @@ function linkTypeChanged() {
 | 
			
		||||
 | 
			
		||||
$linkTypes.change(linkTypeChanged);
 | 
			
		||||
 | 
			
		||||
// return back focus to note text detail after quitting add link
 | 
			
		||||
// the problem is that cursor position is reset
 | 
			
		||||
$dialog.on("hidden.bs.modal", () => noteDetailText.focus());
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    showDialog
 | 
			
		||||
};
 | 
			
		||||
@@ -97,7 +97,7 @@ function AttributesModel() {
 | 
			
		||||
        await showAttributes(attributes);
 | 
			
		||||
 | 
			
		||||
        // attribute might not be rendered immediatelly so could not focus
 | 
			
		||||
        setTimeout(() => $(".attribute-type-select:last").focus(), 100);
 | 
			
		||||
        setTimeout(() => $(".attribute-type-select:last").focus(), 1000);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.deleteAttribute = function(data, event) {
 | 
			
		||||
@@ -169,6 +169,8 @@ function AttributesModel() {
 | 
			
		||||
        infoService.showMessage("Attributes have been saved.");
 | 
			
		||||
 | 
			
		||||
        attributeService.refreshAttributes();
 | 
			
		||||
 | 
			
		||||
        noteDetailService.reload();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function addLastEmptyRow() {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import treeService from '../services/tree.js';
 | 
			
		||||
import server from '../services/server.js';
 | 
			
		||||
import treeCache from "../services/tree_cache.js";
 | 
			
		||||
import treeUtils from "../services/tree_utils.js";
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#branch-prefix-dialog");
 | 
			
		||||
const $form = $("#branch-prefix-form");
 | 
			
		||||
@@ -24,7 +25,7 @@ async function showDialog() {
 | 
			
		||||
 | 
			
		||||
    const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
 | 
			
		||||
 | 
			
		||||
    $noteTitle.html(noteTitle);
 | 
			
		||||
    $noteTitle.text(" - " + noteTitle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function savePrefix() {
 | 
			
		||||
@@ -35,6 +36,8 @@ async function savePrefix() {
 | 
			
		||||
    await treeService.setPrefix(branchId, prefix);
 | 
			
		||||
 | 
			
		||||
    $dialog.modal('hide');
 | 
			
		||||
 | 
			
		||||
    infoService.showMessage("Branch prefix has been saved.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$form.submit(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
import treeService from '../services/tree.js';
 | 
			
		||||
import treeUtils from "../services/tree_utils.js";
 | 
			
		||||
import exportService from "../services/export.js";
 | 
			
		||||
import utils from "../services/utils.js";
 | 
			
		||||
import protectedSessionHolder from "../services/protected_session_holder.js";
 | 
			
		||||
import messagingService from "../services/messaging.js";
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#export-dialog");
 | 
			
		||||
const $form = $("#export-form");
 | 
			
		||||
@@ -9,10 +12,25 @@ const $subtreeFormats = $("#export-subtree-formats");
 | 
			
		||||
const $singleFormats = $("#export-single-formats");
 | 
			
		||||
const $subtreeType = $("#export-type-subtree");
 | 
			
		||||
const $singleType = $("#export-type-single");
 | 
			
		||||
const $exportProgressWrapper = $("#export-progress-count-wrapper");
 | 
			
		||||
const $exportProgressCount = $("#export-progress-count");
 | 
			
		||||
const $exportButton = $("#export-button");
 | 
			
		||||
const $opmlVersions = $("#opml-versions");
 | 
			
		||||
 | 
			
		||||
let exportId = '';
 | 
			
		||||
 | 
			
		||||
async function showDialog(defaultType) {
 | 
			
		||||
    // each opening of the dialog resets the exportId so we don't associate it with previous exports anymore
 | 
			
		||||
    exportId = '';
 | 
			
		||||
    $exportButton.removeAttr("disabled");
 | 
			
		||||
    $exportProgressWrapper.hide();
 | 
			
		||||
    $exportProgressCount.text('0');
 | 
			
		||||
 | 
			
		||||
    if (defaultType === 'subtree') {
 | 
			
		||||
        $subtreeType.prop("checked", true).change();
 | 
			
		||||
 | 
			
		||||
        // to show/hide OPML versions
 | 
			
		||||
        $("input[name=export-subtree-format]:checked").change();
 | 
			
		||||
    }
 | 
			
		||||
    else if (defaultType === 'single') {
 | 
			
		||||
        $singleType.prop("checked", true).change();
 | 
			
		||||
@@ -21,6 +39,8 @@ async function showDialog(defaultType) {
 | 
			
		||||
        throw new Error("Unrecognized type " + defaultType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $("#opml-v2").prop("checked", true); // setting default
 | 
			
		||||
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
@@ -32,6 +52,9 @@ async function showDialog(defaultType) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$form.submit(() => {
 | 
			
		||||
    // disabling so export can't be triggered again
 | 
			
		||||
    $exportButton.attr("disabled", "disabled");
 | 
			
		||||
 | 
			
		||||
    const exportType = $dialog.find("input[name='export-type']:checked").val();
 | 
			
		||||
 | 
			
		||||
    if (!exportType) {
 | 
			
		||||
@@ -44,15 +67,23 @@ $form.submit(() => {
 | 
			
		||||
        ? $("input[name=export-subtree-format]:checked").val()
 | 
			
		||||
        : $("input[name=export-single-format]:checked").val();
 | 
			
		||||
 | 
			
		||||
    const exportVersion = exportFormat === 'opml' ? $dialog.find("input[name='opml-version']:checked").val() : "1.0";
 | 
			
		||||
 | 
			
		||||
    const currentNode = treeService.getCurrentNode();
 | 
			
		||||
 | 
			
		||||
    exportService.exportBranch(currentNode.data.branchId, exportType, exportFormat);
 | 
			
		||||
 | 
			
		||||
    $dialog.modal('hide');
 | 
			
		||||
    exportBranch(currentNode.data.branchId, exportType, exportFormat, exportVersion);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function exportBranch(branchId, type, format, version) {
 | 
			
		||||
    exportId = utils.randomString(10);
 | 
			
		||||
 | 
			
		||||
    const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}/${version}/${exportId}`;
 | 
			
		||||
 | 
			
		||||
    utils.download(url);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$('input[name=export-type]').change(function () {
 | 
			
		||||
    if (this.value === 'subtree') {
 | 
			
		||||
        if ($("input[name=export-subtree-format]:checked").length === 0) {
 | 
			
		||||
@@ -72,6 +103,39 @@ $('input[name=export-type]').change(function () {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$('input[name=export-subtree-format]').change(function () {
 | 
			
		||||
    if (this.value === 'opml') {
 | 
			
		||||
        $opmlVersions.slideDown();
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        $opmlVersions.slideUp();
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
messagingService.subscribeToMessages(async message => {
 | 
			
		||||
    if (message.type === 'export-error') {
 | 
			
		||||
        infoService.showError(message.message);
 | 
			
		||||
        $dialog.modal('hide');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!message.exportId || message.exportId !== exportId) {
 | 
			
		||||
        // incoming messages must correspond to this export instance
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (message.type === 'export-progress-count') {
 | 
			
		||||
        $exportProgressWrapper.slideDown();
 | 
			
		||||
 | 
			
		||||
        $exportProgressCount.text(message.progressCount);
 | 
			
		||||
    }
 | 
			
		||||
    else if (message.type === 'export-finished') {
 | 
			
		||||
        $dialog.modal('hide');
 | 
			
		||||
 | 
			
		||||
        infoService.showMessage("Export finished successfully.");
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    showDialog
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										11
									
								
								src/public/javascripts/dialogs/help.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/public/javascripts/dialogs/help.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
const $dialog = $("#help-dialog");
 | 
			
		||||
 | 
			
		||||
async function showDialog() {
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    showDialog
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								src/public/javascripts/dialogs/import.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/public/javascripts/dialogs/import.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
import treeService from '../services/tree.js';
 | 
			
		||||
import utils from '../services/utils.js';
 | 
			
		||||
import treeUtils from "../services/tree_utils.js";
 | 
			
		||||
import server from "../services/server.js";
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
import messagingService from "../services/messaging.js";
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#import-dialog");
 | 
			
		||||
const $form = $("#import-form");
 | 
			
		||||
const $noteTitle = $dialog.find(".note-title");
 | 
			
		||||
const $fileUploadInput = $("#import-file-upload-input");
 | 
			
		||||
const $importProgressCountWrapper = $("#import-progress-count-wrapper");
 | 
			
		||||
const $importProgressCount = $("#import-progress-count");
 | 
			
		||||
const $importButton = $("#import-button");
 | 
			
		||||
const $safeImportCheckbox = $("#safe-import-checkbox");
 | 
			
		||||
const $shrinkImagesCheckbox = $("#shrink-images-checkbox");
 | 
			
		||||
const $textImportedAsTextCheckbox = $("#text-imported-as-text-checkbox");
 | 
			
		||||
const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox");
 | 
			
		||||
const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
 | 
			
		||||
 | 
			
		||||
let importId;
 | 
			
		||||
 | 
			
		||||
async function showDialog() {
 | 
			
		||||
    // each opening of the dialog resets the importId so we don't associate it with previous imports anymore
 | 
			
		||||
    importId = '';
 | 
			
		||||
    $importProgressCountWrapper.hide();
 | 
			
		||||
    $importProgressCount.text('0');
 | 
			
		||||
    $fileUploadInput.val('').change(); // to trigger Import button disabling listener below
 | 
			
		||||
 | 
			
		||||
    $safeImportCheckbox.prop("checked", true);
 | 
			
		||||
    $shrinkImagesCheckbox.prop("checked", true);
 | 
			
		||||
    $textImportedAsTextCheckbox.prop("checked", true);
 | 
			
		||||
    $codeImportedAsCodeCheckbox.prop("checked", true);
 | 
			
		||||
    $explodeArchivesCheckbox.prop("checked", true);
 | 
			
		||||
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
    const currentNode = treeService.getCurrentNode();
 | 
			
		||||
    $noteTitle.text(await treeUtils.getNoteTitle(currentNode.data.noteId));
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$form.submit(() => {
 | 
			
		||||
    const currentNode = treeService.getCurrentNode();
 | 
			
		||||
 | 
			
		||||
    // disabling so that import is not triggered again.
 | 
			
		||||
    $importButton.attr("disabled", "disabled");
 | 
			
		||||
 | 
			
		||||
    importIntoNote(currentNode.data.noteId);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function importIntoNote(importNoteId) {
 | 
			
		||||
    const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
 | 
			
		||||
 | 
			
		||||
    // we generate it here (and not on opening) for the case when you try to import multiple times from the same
 | 
			
		||||
    // dialog (which shouldn't happen, but still ...)
 | 
			
		||||
    importId = utils.randomString(10);
 | 
			
		||||
 | 
			
		||||
    const options = {
 | 
			
		||||
        safeImport: boolToString($safeImportCheckbox),
 | 
			
		||||
        shrinkImages: boolToString($shrinkImagesCheckbox),
 | 
			
		||||
        textImportedAsText: boolToString($textImportedAsTextCheckbox),
 | 
			
		||||
        codeImportedAsCode: boolToString($codeImportedAsCodeCheckbox),
 | 
			
		||||
        explodeArchives: boolToString($explodeArchivesCheckbox)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    await uploadFiles(importNoteId, files, options);
 | 
			
		||||
 | 
			
		||||
    $dialog.modal('hide');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function uploadFiles(importNoteId, files, options) {
 | 
			
		||||
    let noteId;
 | 
			
		||||
 | 
			
		||||
    for (const file of files) {
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
        formData.append('upload', file);
 | 
			
		||||
        formData.append('importId', importId);
 | 
			
		||||
 | 
			
		||||
        for (const key in options) {
 | 
			
		||||
            formData.append(key, options[key]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ({noteId} = await $.ajax({
 | 
			
		||||
            url: baseApiUrl + 'notes/' + importNoteId + '/import',
 | 
			
		||||
            headers: server.getHeaders(),
 | 
			
		||||
            data: formData,
 | 
			
		||||
            dataType: 'json',
 | 
			
		||||
            type: 'POST',
 | 
			
		||||
            timeout: 60 * 60 * 1000,
 | 
			
		||||
            contentType: false, // NEEDED, DON'T REMOVE THIS
 | 
			
		||||
            processData: false, // NEEDED, DON'T REMOVE THIS
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    infoService.showMessage("Import finished successfully.");
 | 
			
		||||
 | 
			
		||||
    await treeService.reload();
 | 
			
		||||
 | 
			
		||||
    if (noteId) {
 | 
			
		||||
        const node = await treeService.activateNote(noteId);
 | 
			
		||||
 | 
			
		||||
        node.setExpanded(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function boolToString($el) {
 | 
			
		||||
    return $el.is(":checked") ? "true" : "false";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
messagingService.subscribeToMessages(async message => {
 | 
			
		||||
    if (message.type === 'import-error') {
 | 
			
		||||
        infoService.showError(message.message);
 | 
			
		||||
        $dialog.modal('hide');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!message.importId || message.importId !== importId) {
 | 
			
		||||
        // incoming messages must correspond to this import instance
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (message.type === 'import-progress-count') {
 | 
			
		||||
        $importProgressCountWrapper.slideDown();
 | 
			
		||||
 | 
			
		||||
        $importProgressCount.text(message.progressCount);
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$fileUploadInput.change(() => {
 | 
			
		||||
    if ($fileUploadInput.val()) {
 | 
			
		||||
        $importButton.removeAttr("disabled");
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        $importButton.attr("disabled", "disabled");
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    showDialog,
 | 
			
		||||
    uploadFiles
 | 
			
		||||
}
 | 
			
		||||
@@ -6,8 +6,6 @@ const $dialog = $("#jump-to-note-dialog");
 | 
			
		||||
const $autoComplete = $("#jump-to-note-autocomplete");
 | 
			
		||||
const $showInFullTextButton = $("#show-in-full-text-button");
 | 
			
		||||
 | 
			
		||||
$dialog.on("shown.bs.modal", e => $autoComplete.focus());
 | 
			
		||||
 | 
			
		||||
async function showDialog() {
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								src/public/javascripts/dialogs/note_info.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/public/javascripts/dialogs/note_info.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import noteDetailService from '../services/note_detail.js';
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#note-info-dialog");
 | 
			
		||||
const $noteId = $("#note-info-note-id");
 | 
			
		||||
const $dateCreated = $("#note-info-date-created");
 | 
			
		||||
const $dateModified = $("#note-info-date-modified");
 | 
			
		||||
const $type = $("#note-info-type");
 | 
			
		||||
const $mime = $("#note-info-mime");
 | 
			
		||||
const $okButton = $("#note-info-ok-button");
 | 
			
		||||
 | 
			
		||||
function showDialog() {
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
 | 
			
		||||
    const currentNote = noteDetailService.getCurrentNote();
 | 
			
		||||
 | 
			
		||||
    $noteId.text(currentNote.noteId);
 | 
			
		||||
    $dateCreated.text(currentNote.dateCreated);
 | 
			
		||||
    $dateModified.text(currentNote.dateModified);
 | 
			
		||||
    $type.text(currentNote.type);
 | 
			
		||||
    $mime.text(currentNote.mime);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$okButton.click(() => $dialog.modal('hide'));
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    showDialog
 | 
			
		||||
};
 | 
			
		||||
@@ -8,7 +8,7 @@ function showDialog() {
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
 | 
			
		||||
    const noteText = noteDetailService.getCurrentNote().content;
 | 
			
		||||
    const noteText = noteDetailService.getCurrentNote().noteContent.content;
 | 
			
		||||
 | 
			
		||||
    $noteSource.text(formatHtml(noteText));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ import server from '../services/server.js';
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
import zoomService from "../services/zoom.js";
 | 
			
		||||
import utils from "../services/utils.js";
 | 
			
		||||
import cssLoader from "../services/css_loader.js";
 | 
			
		||||
 | 
			
		||||
const $dialog = $("#options-dialog");
 | 
			
		||||
 | 
			
		||||
@@ -44,10 +45,28 @@ addTabHandler((function() {
 | 
			
		||||
    const $zoomFactorSelect = $("#zoom-factor-select");
 | 
			
		||||
    const $leftPaneMinWidth = $("#left-pane-min-width");
 | 
			
		||||
    const $leftPaneWidthPercent = $("#left-pane-width-percent");
 | 
			
		||||
    const $html = $("html");
 | 
			
		||||
    const $mainFontSize = $("#main-font-size");
 | 
			
		||||
    const $treeFontSize = $("#tree-font-size");
 | 
			
		||||
    const $detailFontSize = $("#detail-font-size");
 | 
			
		||||
    const $body = $("body");
 | 
			
		||||
    const $container = $("#container");
 | 
			
		||||
 | 
			
		||||
    function optionsLoaded(options) {
 | 
			
		||||
    async function optionsLoaded(options) {
 | 
			
		||||
        const themes = [
 | 
			
		||||
            { val: 'white', title: 'White' },
 | 
			
		||||
            { val: 'dark', title: 'Dark' },
 | 
			
		||||
            { val: 'black', title: 'Black' }
 | 
			
		||||
        ].concat(await server.get('options/user-themes'));
 | 
			
		||||
 | 
			
		||||
        $themeSelect.empty();
 | 
			
		||||
 | 
			
		||||
        for (const theme of themes) {
 | 
			
		||||
            $themeSelect.append($("<option>")
 | 
			
		||||
                .attr("value", theme.val)
 | 
			
		||||
                .attr("data-note-id", theme.noteId)
 | 
			
		||||
                .html(theme.title));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $themeSelect.val(options.theme);
 | 
			
		||||
 | 
			
		||||
        if (utils.isElectron()) {
 | 
			
		||||
@@ -59,21 +78,35 @@ addTabHandler((function() {
 | 
			
		||||
 | 
			
		||||
        $leftPaneMinWidth.val(options.leftPaneMinWidth);
 | 
			
		||||
        $leftPaneWidthPercent.val(options.leftPaneWidthPercent);
 | 
			
		||||
 | 
			
		||||
        $mainFontSize.val(options.mainFontSize);
 | 
			
		||||
        $treeFontSize.val(options.treeFontSize);
 | 
			
		||||
        $detailFontSize.val(options.detailFontSize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $themeSelect.change(function() {
 | 
			
		||||
        const newTheme = $(this).val();
 | 
			
		||||
 | 
			
		||||
        $html.attr("class", "theme-" + newTheme);
 | 
			
		||||
        for (const clazz of Array.from($body[0].classList)) { // create copy to safely iterate over while removing classes
 | 
			
		||||
            if (clazz.startsWith("theme-")) {
 | 
			
		||||
                $body.removeClass(clazz);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const noteId = $(this).find(":selected").attr("data-note-id");
 | 
			
		||||
 | 
			
		||||
        if (noteId) {
 | 
			
		||||
            // make sure the CSS is loaded
 | 
			
		||||
            // if the CSS has been loaded and then updated then the changes won't take effect though
 | 
			
		||||
            cssLoader.requireCss(`/api/notes/download/${noteId}`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $body.addClass("theme-" + newTheme);
 | 
			
		||||
 | 
			
		||||
        server.put('options/theme/' + newTheme);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $zoomFactorSelect.change(function() {
 | 
			
		||||
        const newZoomFactor = $(this).val();
 | 
			
		||||
 | 
			
		||||
        zoomService.setZoomFactorAndSave(newZoomFactor);
 | 
			
		||||
    });
 | 
			
		||||
    $zoomFactorSelect.change(function() { zoomService.setZoomFactorAndSave($(this).val()); });
 | 
			
		||||
 | 
			
		||||
    function resizeLeftPanel() {
 | 
			
		||||
        const leftPanePercent = parseInt($leftPaneWidthPercent.val());
 | 
			
		||||
@@ -83,20 +116,42 @@ addTabHandler((function() {
 | 
			
		||||
        $container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $leftPaneMinWidth.change(function() {
 | 
			
		||||
        const newMinWidth = $(this).val();
 | 
			
		||||
    $leftPaneMinWidth.change(async function() {
 | 
			
		||||
        await server.put('options/leftPaneMinWidth/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeLeftPanel();
 | 
			
		||||
 | 
			
		||||
        server.put('options/leftPaneMinWidth/' + newMinWidth);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $leftPaneWidthPercent.change(function() {
 | 
			
		||||
        const newWidthPercent = $(this).val();
 | 
			
		||||
    $leftPaneWidthPercent.change(async function() {
 | 
			
		||||
        await server.put('options/leftPaneWidthPercent/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        resizeLeftPanel();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
        server.put('options/leftPaneWidthPercent/' + newWidthPercent);
 | 
			
		||||
    function applyFontSizes() {
 | 
			
		||||
        console.log($mainFontSize.val() + "% !important");
 | 
			
		||||
 | 
			
		||||
        $body.get(0).style.setProperty("--main-font-size", $mainFontSize.val() + "%");
 | 
			
		||||
        $body.get(0).style.setProperty("--tree-font-size", $treeFontSize.val() + "%");
 | 
			
		||||
        $body.get(0).style.setProperty("--detail-font-size", $detailFontSize.val() + "%");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $mainFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/mainFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $treeFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/treeFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $detailFontSize.change(async function() {
 | 
			
		||||
        await server.put('options/detailFontSize/' + $(this).val());
 | 
			
		||||
 | 
			
		||||
        applyFontSizes();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
@@ -198,15 +253,17 @@ addTabHandler((async function () {
 | 
			
		||||
    const $syncVersion = $("#sync-version");
 | 
			
		||||
    const $buildDate = $("#build-date");
 | 
			
		||||
    const $buildRevision = $("#build-revision");
 | 
			
		||||
    const $dataDirectory = $("#data-directory");
 | 
			
		||||
 | 
			
		||||
    const appInfo = await server.get('app-info');
 | 
			
		||||
 | 
			
		||||
    $appVersion.html(appInfo.appVersion);
 | 
			
		||||
    $dbVersion.html(appInfo.dbVersion);
 | 
			
		||||
    $syncVersion.html(appInfo.syncVersion);
 | 
			
		||||
    $buildDate.html(appInfo.buildDate);
 | 
			
		||||
    $buildRevision.html(appInfo.buildRevision);
 | 
			
		||||
    $appVersion.text(appInfo.appVersion);
 | 
			
		||||
    $dbVersion.text(appInfo.dbVersion);
 | 
			
		||||
    $syncVersion.text(appInfo.syncVersion);
 | 
			
		||||
    $buildDate.text(appInfo.buildDate);
 | 
			
		||||
    $buildRevision.text(appInfo.buildRevision);
 | 
			
		||||
    $buildRevision.attr('href', 'https://github.com/zadam/trilium/commit/' + appInfo.buildRevision);
 | 
			
		||||
    $dataDirectory.text(appInfo.dataDirectory);
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
})());
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import utils from '../services/utils.js';
 | 
			
		||||
import libraryLoader from '../services/library_loader.js';
 | 
			
		||||
import server from '../services/server.js';
 | 
			
		||||
import infoService from "../services/info.js";
 | 
			
		||||
@@ -8,14 +7,17 @@ const $query = $('#sql-console-query');
 | 
			
		||||
const $executeButton = $('#sql-console-execute');
 | 
			
		||||
const $resultHead = $('#sql-console-results thead');
 | 
			
		||||
const $resultBody = $('#sql-console-results tbody');
 | 
			
		||||
const $tables = $("#sql-console-tables");
 | 
			
		||||
 | 
			
		||||
let codeEditor;
 | 
			
		||||
 | 
			
		||||
$dialog.on("shown.bs.modal", e => initEditor());
 | 
			
		||||
 | 
			
		||||
function showDialog() {
 | 
			
		||||
async function showDialog() {
 | 
			
		||||
    glob.activeDialog = $dialog;
 | 
			
		||||
 | 
			
		||||
    await showTables();
 | 
			
		||||
 | 
			
		||||
    $dialog.modal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -96,6 +98,32 @@ async function execute(e) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function showTables() {
 | 
			
		||||
    const tables = await server.get('sql/schema');
 | 
			
		||||
 | 
			
		||||
    $tables.empty();
 | 
			
		||||
 | 
			
		||||
    for (const table of tables) {
 | 
			
		||||
        const $tableLink = $('<button class="btn">').text(table.name);
 | 
			
		||||
 | 
			
		||||
        const $columns = $("<table>");
 | 
			
		||||
 | 
			
		||||
        for (const column of table.columns) {
 | 
			
		||||
            $columns.append(
 | 
			
		||||
                $("<tr>")
 | 
			
		||||
                    .append($("<td>").text(column.name))
 | 
			
		||||
                    .append($("<td>").text(column.type))
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $tables.append($tableLink).append(" ");
 | 
			
		||||
 | 
			
		||||
        $tableLink
 | 
			
		||||
            .tooltip({html: true, title: $columns.html()})
 | 
			
		||||
            .click(() => codeEditor.setValue("SELECT * FROM " + table.name + " LIMIT 100"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$query.bind('keydown', 'ctrl+return', execute);
 | 
			
		||||
 | 
			
		||||
$executeButton.click(execute);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								src/public/javascripts/entities/attribute.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/public/javascripts/entities/attribute.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
class Attribute {
 | 
			
		||||
    constructor(treeCache, row) {
 | 
			
		||||
        this.treeCache = treeCache;
 | 
			
		||||
        /** @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;
 | 
			
		||||
        /** @param {boolean} isDeleted */
 | 
			
		||||
        this.isDeleted = row.isDeleted;
 | 
			
		||||
        /** @param {string} dateCreated */
 | 
			
		||||
        this.dateCreated = row.dateCreated;
 | 
			
		||||
        /** @param {string} dateModified */
 | 
			
		||||
        this.dateModified = row.dateModified;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** @returns {NoteShort} */
 | 
			
		||||
    async getNote() {
 | 
			
		||||
        return await this.treeCache.getNote(this.noteId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get toString() {
 | 
			
		||||
        return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default Attribute;
 | 
			
		||||
@@ -8,15 +8,13 @@ class NoteFull extends NoteShort {
 | 
			
		||||
        super(treeCache, row);
 | 
			
		||||
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.content = row.content;
 | 
			
		||||
        this.noteContent = row.noteContent;
 | 
			
		||||
 | 
			
		||||
        if (this.content !== "" && this.isJson()) {
 | 
			
		||||
            try {
 | 
			
		||||
                /** @param {object} */
 | 
			
		||||
                this.jsonContent = JSON.parse(this.content);
 | 
			
		||||
            }
 | 
			
		||||
            catch(e) {}
 | 
			
		||||
        }
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.dateCreated = row.dateCreated;
 | 
			
		||||
 | 
			
		||||
        /** @param {string} */
 | 
			
		||||
        this.dateModified = row.dateModified;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,10 @@
 | 
			
		||||
import server from '../services/server.js';
 | 
			
		||||
 | 
			
		||||
const LABEL = 'label';
 | 
			
		||||
const LABEL_DEFINITION = 'label-definition';
 | 
			
		||||
const RELATION = 'relation';
 | 
			
		||||
const RELATION_DEFINITION = 'relation-definition';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This note's representation is used in note tree and is kept in TreeCache.
 | 
			
		||||
 * Its notable omission is the note content.
 | 
			
		||||
@@ -71,6 +78,140 @@ class NoteShort {
 | 
			
		||||
        return await this.treeCache.getNotes(this.getChildNoteIds());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - attribute name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>}
 | 
			
		||||
     */
 | 
			
		||||
    async getAttributes(name) {
 | 
			
		||||
        if (!this.attributeCache) {
 | 
			
		||||
            this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (name) {
 | 
			
		||||
            return this.attributeCache.filter(attr => attr.name === name);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return this.attributeCache;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - label name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getLabels(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - label name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getLabelDefinitions(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - relation name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getRelations(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} [name] - relation name to filter
 | 
			
		||||
     * @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationDefinitions(name) {
 | 
			
		||||
        return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasAttribute(type, name) {
 | 
			
		||||
        return !!await this.getAttribute(type, name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is  returned. Returns null if there's no such attribute belonging to this note.
 | 
			
		||||
     */
 | 
			
		||||
    async getAttribute(type, name) {
 | 
			
		||||
        const attributes = await this.getAttributes();
 | 
			
		||||
 | 
			
		||||
        return attributes.find(attr => attr.type === type && attr.name === name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} type - attribute type (label, relation, etc.)
 | 
			
		||||
     * @param {string} name - attribute name
 | 
			
		||||
     * @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
 | 
			
		||||
     */
 | 
			
		||||
    async getAttributeValue(type, name) {
 | 
			
		||||
        const attr = await this.getAttribute(type, name);
 | 
			
		||||
 | 
			
		||||
        return attr ? attr.value : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<boolean>} true if label exists (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<boolean>} true if relation exists (including inherited)
 | 
			
		||||
     */
 | 
			
		||||
    async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<Attribute>} label if it exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getLabel(name) { return await this.getAttribute(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<Attribute>} relation if it exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getRelation(name) { return await this.getAttribute(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - label name
 | 
			
		||||
     * @returns {Promise<string>} label value if label exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name - relation name
 | 
			
		||||
     * @returns {Promise<string>} relation value if relation exists, null otherwise
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param {string} name
 | 
			
		||||
     * @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
 | 
			
		||||
     */
 | 
			
		||||
    async getRelationTarget(name) {
 | 
			
		||||
        const relation = await this.getRelation(name);
 | 
			
		||||
 | 
			
		||||
        return relation ? await repository.getNote(relation.value) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear note's attributes cache to force fresh reload for next attribute request.
 | 
			
		||||
     * Cache is note instance scoped.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateAttributeCache() {
 | 
			
		||||
        this.attributeCache = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get toString() {
 | 
			
		||||
        return `Note(noteId=${this.noteId}, title=${this.title})`;
 | 
			
		||||
    }
 | 
			
		||||
@@ -79,6 +220,7 @@ class NoteShort {
 | 
			
		||||
        const dto = Object.assign({}, this);
 | 
			
		||||
        delete dto.treeCache;
 | 
			
		||||
        delete dto.archived;
 | 
			
		||||
        delete dto.attributeCache;
 | 
			
		||||
 | 
			
		||||
        return dto;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										128
									
								
								src/public/javascripts/mobile.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								src/public/javascripts/mobile.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,128 @@
 | 
			
		||||
import treeService from "./services/tree.js";
 | 
			
		||||
import noteDetailService from "./services/note_detail.js";
 | 
			
		||||
import dragAndDropSetup from "./services/drag_and_drop.js";
 | 
			
		||||
import treeCache from "./services/tree_cache.js";
 | 
			
		||||
import treeBuilder from "./services/tree_builder.js";
 | 
			
		||||
import contextMenuWidget from "./services/context_menu.js";
 | 
			
		||||
import ContextMenuItemsContainer from "./services/context_menu_items_container.js";
 | 
			
		||||
import treeChangesService from "./services/branches.js";
 | 
			
		||||
import utils from "./services/utils.js";
 | 
			
		||||
import treeUtils from "./services/tree_utils.js";
 | 
			
		||||
 | 
			
		||||
const $leftPane = $("#left-pane");
 | 
			
		||||
const $tree = $("#tree");
 | 
			
		||||
const $detail = $("#detail");
 | 
			
		||||
const $closeDetailButton = $("#close-detail-button");
 | 
			
		||||
 | 
			
		||||
function togglePanes() {
 | 
			
		||||
    if (!$leftPane.is(":visible") || !$detail.is(":visible")) {
 | 
			
		||||
        $detail.toggleClass("d-none");
 | 
			
		||||
        $leftPane.toggleClass("d-none");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showDetailPane() {
 | 
			
		||||
    if (!$detail.is(":visible")) {
 | 
			
		||||
        $detail.removeClass("d-none");
 | 
			
		||||
        $leftPane.addClass("d-none");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$closeDetailButton.click(() => {
 | 
			
		||||
    // no page is opened
 | 
			
		||||
    document.location.hash = '-';
 | 
			
		||||
 | 
			
		||||
    togglePanes();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function showTree() {
 | 
			
		||||
    const tree = await treeService.loadTree();
 | 
			
		||||
 | 
			
		||||
    $tree.fancytree({
 | 
			
		||||
        autoScroll: true,
 | 
			
		||||
        extensions: ["dnd5", "clones"],
 | 
			
		||||
        source: tree,
 | 
			
		||||
        scrollParent: $tree,
 | 
			
		||||
        minExpandLevel: 2, // root can't be collapsed
 | 
			
		||||
        activate: (event, data) => {
 | 
			
		||||
            const node = data.node;
 | 
			
		||||
            const noteId = node.data.noteId;
 | 
			
		||||
 | 
			
		||||
            treeService.clearSelectedNodes();
 | 
			
		||||
 | 
			
		||||
            treeService.setCurrentNotePathToHash(node);
 | 
			
		||||
 | 
			
		||||
            showDetailPane();
 | 
			
		||||
 | 
			
		||||
            noteDetailService.switchToNote(noteId, true);
 | 
			
		||||
        },
 | 
			
		||||
        expand: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, true),
 | 
			
		||||
        collapse: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, false),
 | 
			
		||||
        init: (event, data) => treeService.treeInitialized(), // don't collapse to short form
 | 
			
		||||
        dnd5: dragAndDropSetup,
 | 
			
		||||
        lazyLoad: function(event, data) {
 | 
			
		||||
            const noteId = data.node.data.noteId;
 | 
			
		||||
 | 
			
		||||
            data.result = treeCache.getNote(noteId).then(note => treeBuilder.prepareBranch(note));
 | 
			
		||||
        },
 | 
			
		||||
        clones: {
 | 
			
		||||
            highlightActiveClones: true
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$("#note-menu-button").click(async e => {
 | 
			
		||||
    const node = treeService.getCurrentNode();
 | 
			
		||||
    const branch = await treeCache.getBranch(node.data.branchId);
 | 
			
		||||
    const note = await treeCache.getNote(node.data.noteId);
 | 
			
		||||
    const parentNote = await treeCache.getNote(branch.parentNoteId);
 | 
			
		||||
    const isNotRoot = note.noteId !== 'root';
 | 
			
		||||
 | 
			
		||||
    const itemsContainer = new ContextMenuItemsContainer([
 | 
			
		||||
        {title: "Insert note after", cmd: "insertNoteAfter", uiIcon: "plus"},
 | 
			
		||||
        {title: "Insert child note", cmd: "insertChildNote", uiIcon: "plus"},
 | 
			
		||||
        {title: "Delete this note", cmd: "delete", uiIcon: "trash"}
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    itemsContainer.enableItem("insertNoteAfter", isNotRoot && parentNote.type !== 'search');
 | 
			
		||||
    itemsContainer.enableItem("insertChildNote", note.type !== 'search');
 | 
			
		||||
    itemsContainer.enableItem("delete", isNotRoot && parentNote.type !== 'search');
 | 
			
		||||
 | 
			
		||||
    contextMenuWidget.initContextMenu(e, itemsContainer, (event, cmd) => {
 | 
			
		||||
        if (cmd === "insertNoteAfter") {
 | 
			
		||||
            const parentNoteId = node.data.parentNoteId;
 | 
			
		||||
            const isProtected = treeUtils.getParentProtectedStatus(node);
 | 
			
		||||
 | 
			
		||||
            treeService.createNote(node, parentNoteId, 'after', isProtected);
 | 
			
		||||
        }
 | 
			
		||||
        else if (cmd === "insertChildNote") {
 | 
			
		||||
            treeService.createNote(node, node.data.noteId, 'into');
 | 
			
		||||
        }
 | 
			
		||||
        else if (cmd === "delete") {
 | 
			
		||||
            treeChangesService.deleteNodes([node]);
 | 
			
		||||
 | 
			
		||||
            // move to the tree
 | 
			
		||||
            togglePanes();
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            throw new Error("Unrecognized command " + cmd);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#switch-to-desktop-button").click(() => {
 | 
			
		||||
    utils.setCookie('trilium-device', 'desktop');
 | 
			
		||||
 | 
			
		||||
    utils.reloadApp();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#log-out-button").click(() => {
 | 
			
		||||
    $("#logout-form").submit();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// this is done so that startNotePath is not used
 | 
			
		||||
if (!document.location.hash) {
 | 
			
		||||
    document.location.hash = '-';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
showTree();
 | 
			
		||||
@@ -13,13 +13,25 @@ const $savedIndicator = $("#saved-indicator");
 | 
			
		||||
 | 
			
		||||
let attributePromise;
 | 
			
		||||
 | 
			
		||||
async function refreshAttributes() {
 | 
			
		||||
function invalidateAttributes() {
 | 
			
		||||
    attributePromise = null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function reloadAttributes() {
 | 
			
		||||
    attributePromise = server.get('notes/' + noteDetailService.getCurrentNoteId() + '/attributes');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function refreshAttributes() {
 | 
			
		||||
    reloadAttributes();
 | 
			
		||||
 | 
			
		||||
    await showAttributes();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getAttributes() {
 | 
			
		||||
    if (!attributePromise) {
 | 
			
		||||
        reloadAttributes();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return await attributePromise;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -73,8 +85,11 @@ async function showAttributes() {
 | 
			
		||||
        $promotedAttributesContainer.empty().append($tbody);
 | 
			
		||||
    }
 | 
			
		||||
    else if (note.type !== 'relation-map') {
 | 
			
		||||
        if (attributes.length > 0) {
 | 
			
		||||
            for (const attribute of attributes) {
 | 
			
		||||
        // display only "own" notes
 | 
			
		||||
        const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
 | 
			
		||||
 | 
			
		||||
        if (ownedAttributes.length > 0) {
 | 
			
		||||
            for (const attribute of ownedAttributes) {
 | 
			
		||||
                if (attribute.type === 'label') {
 | 
			
		||||
                    $attributeListInner.append(utils.formatLabel(attribute) + " ");
 | 
			
		||||
                }
 | 
			
		||||
@@ -120,7 +135,9 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
 | 
			
		||||
    const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
 | 
			
		||||
 | 
			
		||||
    const $actionCell = $("<td>");
 | 
			
		||||
    const $multiplicityCell = $("<td>").addClass("multiplicity");
 | 
			
		||||
    const $multiplicityCell = $("<td>")
 | 
			
		||||
        .addClass("multiplicity")
 | 
			
		||||
        .attr("nowrap", true);
 | 
			
		||||
 | 
			
		||||
    $tr
 | 
			
		||||
        .append($labelCell)
 | 
			
		||||
@@ -143,7 +160,7 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
 | 
			
		||||
                $input.autocomplete({
 | 
			
		||||
                    appendTo: document.querySelector('body'),
 | 
			
		||||
                    hint: false,
 | 
			
		||||
                    autoselect: true,
 | 
			
		||||
                    autoselect: false,
 | 
			
		||||
                    openOnFocus: true,
 | 
			
		||||
                    minLength: 0,
 | 
			
		||||
                    tabAutocomplete: false
 | 
			
		||||
@@ -286,5 +303,6 @@ async function promotedAttributeChanged(event) {
 | 
			
		||||
export default {
 | 
			
		||||
    getAttributes,
 | 
			
		||||
    showAttributes,
 | 
			
		||||
    refreshAttributes
 | 
			
		||||
    refreshAttributes,
 | 
			
		||||
    invalidateAttributes
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										143
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										143
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							@@ -1,143 +0,0 @@
 | 
			
		||||
import addLinkDialog from '../dialogs/add_link.js';
 | 
			
		||||
import jumpToNoteDialog from '../dialogs/jump_to_note.js';
 | 
			
		||||
import attributesDialog from '../dialogs/attributes.js';
 | 
			
		||||
import noteRevisionsDialog from '../dialogs/note_revisions.js';
 | 
			
		||||
import noteSourceDialog from '../dialogs/note_source.js';
 | 
			
		||||
import recentChangesDialog from '../dialogs/recent_changes.js';
 | 
			
		||||
import optionsDialog from '../dialogs/options.js';
 | 
			
		||||
import sqlConsoleDialog from '../dialogs/sql_console.js';
 | 
			
		||||
import markdownImportDialog from '../dialogs/markdown_import.js';
 | 
			
		||||
import exportDialog from '../dialogs/export.js';
 | 
			
		||||
 | 
			
		||||
import cloning from './cloning.js';
 | 
			
		||||
import contextMenu from './tree_context_menu.js';
 | 
			
		||||
import dragAndDropSetup from './drag_and_drop.js';
 | 
			
		||||
import exportService from './export.js';
 | 
			
		||||
import link from './link.js';
 | 
			
		||||
import messagingService from './messaging.js';
 | 
			
		||||
import noteDetailService from './note_detail.js';
 | 
			
		||||
import noteType from './note_type.js';
 | 
			
		||||
import protected_session from './protected_session.js';
 | 
			
		||||
import searchNotesService from './search_notes.js';
 | 
			
		||||
import FrontendScriptApi from './frontend_script_api.js';
 | 
			
		||||
import ScriptContext from './script_context.js';
 | 
			
		||||
import sync from './sync.js';
 | 
			
		||||
import treeService from './tree.js';
 | 
			
		||||
import treeChanges from './branches.js';
 | 
			
		||||
import treeUtils from './tree_utils.js';
 | 
			
		||||
import utils from './utils.js';
 | 
			
		||||
import server from './server.js';
 | 
			
		||||
import entrypoints from './entrypoints.js';
 | 
			
		||||
import tooltip from './tooltip.js';
 | 
			
		||||
import bundle from "./bundle.js";
 | 
			
		||||
import treeCache from "./tree_cache.js";
 | 
			
		||||
import libraryLoader from "./library_loader.js";
 | 
			
		||||
 | 
			
		||||
// required for CKEditor image upload plugin
 | 
			
		||||
window.glob.getCurrentNode = treeService.getCurrentNode;
 | 
			
		||||
window.glob.getHeaders = server.getHeaders;
 | 
			
		||||
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
 | 
			
		||||
// this is required by CKEditor when uploading images
 | 
			
		||||
window.glob.noteChanged = noteDetailService.noteChanged;
 | 
			
		||||
window.glob.refreshTree = treeService.reload;
 | 
			
		||||
 | 
			
		||||
// required for ESLint plugin
 | 
			
		||||
window.glob.getCurrentNote = noteDetailService.getCurrentNote;
 | 
			
		||||
window.glob.requireLibrary = libraryLoader.requireLibrary;
 | 
			
		||||
window.glob.ESLINT = libraryLoader.ESLINT;
 | 
			
		||||
 | 
			
		||||
window.onerror = function (msg, url, lineNo, columnNo, error) {
 | 
			
		||||
    const string = msg.toLowerCase();
 | 
			
		||||
 | 
			
		||||
    let message = "Uncaught error: ";
 | 
			
		||||
 | 
			
		||||
    if (string.includes("Cannot read property 'defaultView' of undefined")) {
 | 
			
		||||
        // ignore this specific error which is very common but we don't know where it comes from
 | 
			
		||||
        // and it seems to be harmless
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    else if (string.includes("script error")) {
 | 
			
		||||
        message += 'No details available';
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        message += [
 | 
			
		||||
            'Message: ' + msg,
 | 
			
		||||
            'URL: ' + url,
 | 
			
		||||
            'Line: ' + lineNo,
 | 
			
		||||
            'Column: ' + columnNo,
 | 
			
		||||
            'Error object: ' + JSON.stringify(error)
 | 
			
		||||
        ].join(' - ');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    messagingService.logError(message);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
$("#logout-button").toggle(!utils.isElectron());
 | 
			
		||||
 | 
			
		||||
if (utils.isElectron()) {
 | 
			
		||||
    require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
 | 
			
		||||
        // this might occur when day note had to be created
 | 
			
		||||
        if (!await treeCache.getNote(parentNoteId)) {
 | 
			
		||||
            await treeService.reload();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await treeService.activateNote(parentNoteId);
 | 
			
		||||
 | 
			
		||||
        setTimeout(async () => {
 | 
			
		||||
            const parentNode = treeService.getCurrentNode();
 | 
			
		||||
 | 
			
		||||
            const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', parentNode.data.isProtected);
 | 
			
		||||
 | 
			
		||||
            await treeService.activateNote(note.noteId);
 | 
			
		||||
 | 
			
		||||
        }, 500);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function exec(cmd) {
 | 
			
		||||
    document.execCommand(cmd);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (utils.isElectron() && utils.isMac()) {
 | 
			
		||||
    utils.bindShortcut('ctrl+c', () => exec("copy"));
 | 
			
		||||
    utils.bindShortcut('ctrl+v', () => exec('paste'));
 | 
			
		||||
    utils.bindShortcut('ctrl+x', () => exec('cut'));
 | 
			
		||||
    utils.bindShortcut('ctrl+a', () => exec('selectAll'));
 | 
			
		||||
    utils.bindShortcut('ctrl+z', () => exec('undo'));
 | 
			
		||||
    utils.bindShortcut('ctrl+y', () => exec('redo'));
 | 
			
		||||
 | 
			
		||||
    utils.bindShortcut('meta+c', () => exec("copy"));
 | 
			
		||||
    utils.bindShortcut('meta+v', () => exec('paste'));
 | 
			
		||||
    utils.bindShortcut('meta+x', () => exec('cut'));
 | 
			
		||||
    utils.bindShortcut('meta+a', () => exec('selectAll'));
 | 
			
		||||
    utils.bindShortcut('meta+z', () => exec('undo'));
 | 
			
		||||
    utils.bindShortcut('meta+y', () => exec('redo'));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$("#export-note-button").click(function () {
 | 
			
		||||
    if ($(this).hasClass("disabled")) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exportDialog.showDialog('single');
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
treeService.showTree();
 | 
			
		||||
 | 
			
		||||
entrypoints.registerEntrypoints();
 | 
			
		||||
 | 
			
		||||
tooltip.setupTooltip();
 | 
			
		||||
 | 
			
		||||
bundle.executeStartupBundles();
 | 
			
		||||
@@ -9,7 +9,7 @@ async function getAndExecuteBundle(noteId, originEntity = null) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function executeBundle(bundle, originEntity) {
 | 
			
		||||
    const apiContext = ScriptContext(bundle.note, bundle.allNotes, originEntity);
 | 
			
		||||
    const apiContext = await ScriptContext(bundle.noteId, bundle.allNoteIds, originEntity);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        return await (function () {
 | 
			
		||||
@@ -17,7 +17,7 @@ async function executeBundle(bundle, originEntity) {
 | 
			
		||||
        }.call(apiContext));
 | 
			
		||||
    }
 | 
			
		||||
    catch (e) {
 | 
			
		||||
        infoService.showAndLogError(`Execution of script "${bundle.note.title}" (${bundle.note.noteId}) failed with error: ${e.message}`);
 | 
			
		||||
        infoService.showAndLogError(`Execution of ${bundle.noteId} failed with error: ${e.message}`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -30,9 +30,13 @@ async function executeStartupBundles() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function executeRelationBundles(note, relationName) {
 | 
			
		||||
    const bundlesToRun = await server.get("script/relation/" + note.noteId + "/" + relationName);
 | 
			
		||||
    note.bundleCache = note.bundleCache || {};
 | 
			
		||||
 | 
			
		||||
    for (const bundle of bundlesToRun) {
 | 
			
		||||
    if (!note.bundleCache[relationName]) {
 | 
			
		||||
        note.bundleCache[relationName] = await server.get("script/relation/" + note.noteId + "/" + relationName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (const bundle of note.bundleCache[relationName]) {
 | 
			
		||||
        await executeBundle(bundle, note);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
const $contextMenuContainer = $("#context-menu-container");
 | 
			
		||||
 | 
			
		||||
function initContextMenu(event, contextMenuItems, selectContextMenuItem) {
 | 
			
		||||
let dateContextMenuOpenedMs = 0;
 | 
			
		||||
 | 
			
		||||
function initContextMenu(event, itemContainer, selectContextMenuItem) {
 | 
			
		||||
    event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
    $contextMenuContainer.empty();
 | 
			
		||||
 | 
			
		||||
    for (const item of contextMenuItems) {
 | 
			
		||||
    for (const item of itemContainer.getItems()) {
 | 
			
		||||
        if (item.title === '----') {
 | 
			
		||||
            $contextMenuContainer.append($("<div>").addClass("dropdown-divider"));
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -53,6 +57,8 @@ function initContextMenu(event, contextMenuItems, selectContextMenuItem) {
 | 
			
		||||
        top = event.pageY - 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dateContextMenuOpenedMs = Date.now();
 | 
			
		||||
 | 
			
		||||
    $contextMenuContainer.css({
 | 
			
		||||
        display: "block",
 | 
			
		||||
        top: top,
 | 
			
		||||
@@ -60,8 +66,18 @@ function initContextMenu(event, contextMenuItems, selectContextMenuItem) {
 | 
			
		||||
    }).addClass("show");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).click(() => $contextMenuContainer.hide());
 | 
			
		||||
$(document).click(() => hideContextMenu());
 | 
			
		||||
 | 
			
		||||
function hideContextMenu() {
 | 
			
		||||
    // this date checking comes from change in FF66 - https://github.com/zadam/trilium/issues/468
 | 
			
		||||
    // "contextmenu" event also triggers "click" event which depending on the timing can close just opened context menu
 | 
			
		||||
    // we might filter out right clicks, but then it's better if even right clicks close the context menu
 | 
			
		||||
    if (Date.now() - dateContextMenuOpenedMs > 300) {
 | 
			
		||||
        $contextMenuContainer.hide();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    initContextMenu
 | 
			
		||||
    initContextMenu,
 | 
			
		||||
    hideContextMenu
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,28 @@
 | 
			
		||||
class ContextMenuItemsContainer {
 | 
			
		||||
    constructor(items) {
 | 
			
		||||
        // clone the item array and the items themselves
 | 
			
		||||
        this.items = items.map(item => Object.assign({}, item));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hideItem(cmd, hidden = true) {
 | 
			
		||||
        if (hidden) {
 | 
			
		||||
            this.items = this.items.filter(item => item.cmd !== cmd);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enableItem(cmd, enabled) {
 | 
			
		||||
        const item = this.items.find(item => item.cmd === cmd);
 | 
			
		||||
 | 
			
		||||
        if (!item) {
 | 
			
		||||
            throw new Error(`Command ${cmd} has not been found!`);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        item.enabled = enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getItems() {
 | 
			
		||||
        return this.items;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default ContextMenuItemsContainer;
 | 
			
		||||
							
								
								
									
										13
									
								
								src/public/javascripts/services/css_loader.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/public/javascripts/services/css_loader.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
async function requireCss(url) {
 | 
			
		||||
    const css = Array
 | 
			
		||||
        .from(document.querySelectorAll('link'))
 | 
			
		||||
        .map(scr => scr.href);
 | 
			
		||||
 | 
			
		||||
    if (!css.includes(url)) {
 | 
			
		||||
        $('head').append($('<link rel="stylesheet" type="text/css" />').attr('href', url));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    requireCss
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import treeService from './tree.js';
 | 
			
		||||
import treeChangesService from './branches.js';
 | 
			
		||||
import importDialog from '../dialogs/import.js';
 | 
			
		||||
 | 
			
		||||
const dragAndDropSetup = {
 | 
			
		||||
    autoExpandMS: 600,
 | 
			
		||||
@@ -9,6 +10,14 @@ const dragAndDropSetup = {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!data.originalEvent.ctrlKey) {
 | 
			
		||||
            // keep existing selection only if CTRL key is pressed
 | 
			
		||||
            for (const selectedNode of treeService.getSelectedNodes()) {
 | 
			
		||||
                selectedNode.setSelected(false);
 | 
			
		||||
                selectedNode.renderTitle();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        node.setSelected(true);
 | 
			
		||||
 | 
			
		||||
        // this is for dragging notes into relation map
 | 
			
		||||
@@ -24,7 +33,20 @@ const dragAndDropSetup = {
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
    dragEnter: (node, data) => true, // allow drop on any node
 | 
			
		||||
    dragOver: (node, data) => true,
 | 
			
		||||
    dragDrop: (node, data) => {
 | 
			
		||||
        const dataTransfer = data.dataTransfer;
 | 
			
		||||
 | 
			
		||||
        if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
 | 
			
		||||
            importDialog.uploadFiles(node.data.noteId, dataTransfer.files, {
 | 
			
		||||
                safeImport: true,
 | 
			
		||||
                shrinkImages: true,
 | 
			
		||||
                textImportedAsText: true,
 | 
			
		||||
                codeImportedAsCode: true,
 | 
			
		||||
                explodeArchives: true
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // This function MUST be defined to enable dropping of items on the tree.
 | 
			
		||||
            // data.hitMode is 'before', 'after', or 'over'.
 | 
			
		||||
 | 
			
		||||
@@ -32,17 +54,15 @@ const dragAndDropSetup = {
 | 
			
		||||
 | 
			
		||||
            if (data.hitMode === "before") {
 | 
			
		||||
                treeChangesService.moveBeforeNode(selectedNodes, node);
 | 
			
		||||
        }
 | 
			
		||||
        else if (data.hitMode === "after") {
 | 
			
		||||
            } else if (data.hitMode === "after") {
 | 
			
		||||
                treeChangesService.moveAfterNode(selectedNodes, node);
 | 
			
		||||
        }
 | 
			
		||||
        else if (data.hitMode === "over") {
 | 
			
		||||
            } else if (data.hitMode === "over") {
 | 
			
		||||
                treeChangesService.moveToNode(selectedNodes, node);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error("Unknown hitMode=" + data.hitMode);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default dragAndDropSetup;
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
import utils from "./utils.js";
 | 
			
		||||
import treeService from "./tree.js";
 | 
			
		||||
import linkService from "./link.js";
 | 
			
		||||
import fileService from "./file.js";
 | 
			
		||||
import zoomService from "./zoom.js";
 | 
			
		||||
import noteRevisionsDialog from "../dialogs/note_revisions.js";
 | 
			
		||||
import optionsDialog from "../dialogs/options.js";
 | 
			
		||||
@@ -12,6 +11,8 @@ import recentChangesDialog from "../dialogs/recent_changes.js";
 | 
			
		||||
import sqlConsoleDialog from "../dialogs/sql_console.js";
 | 
			
		||||
import searchNotesService from "./search_notes.js";
 | 
			
		||||
import attributesDialog from "../dialogs/attributes.js";
 | 
			
		||||
import helpDialog from "../dialogs/help.js";
 | 
			
		||||
import noteInfoDialog from "../dialogs/note_info.js";
 | 
			
		||||
import protectedSessionService from "./protected_session.js";
 | 
			
		||||
 | 
			
		||||
function registerEntrypoints() {
 | 
			
		||||
@@ -54,16 +55,29 @@ function registerEntrypoints() {
 | 
			
		||||
 | 
			
		||||
    $("#options-button").click(optionsDialog.showDialog);
 | 
			
		||||
 | 
			
		||||
    $("#show-help-button").click(helpDialog.showDialog);
 | 
			
		||||
    utils.bindShortcut('f1', helpDialog.showDialog);
 | 
			
		||||
 | 
			
		||||
    $("#open-sql-console-button").click(sqlConsoleDialog.showDialog);
 | 
			
		||||
    utils.bindShortcut('alt+o', sqlConsoleDialog.showDialog);
 | 
			
		||||
 | 
			
		||||
    $("#show-note-info-button").click(noteInfoDialog.showDialog);
 | 
			
		||||
 | 
			
		||||
    if (utils.isElectron()) {
 | 
			
		||||
        $("#history-navigation").show();
 | 
			
		||||
        $("#history-back-button").click(window.history.back);
 | 
			
		||||
        $("#history-forward-button").click(window.history.forward);
 | 
			
		||||
 | 
			
		||||
        if (utils.isMac()) {
 | 
			
		||||
            // Mac has a different history navigation shortcuts - https://github.com/zadam/trilium/issues/376
 | 
			
		||||
            utils.bindShortcut('meta+left', window.history.back);
 | 
			
		||||
            utils.bindShortcut('meta+right', window.history.forward);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            utils.bindShortcut('alt+left', window.history.back);
 | 
			
		||||
            utils.bindShortcut('alt+right', window.history.forward);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    utils.bindShortcut('alt+m', e => {
 | 
			
		||||
        $(".hide-toggle").toggle();
 | 
			
		||||
@@ -87,13 +101,18 @@ function registerEntrypoints() {
 | 
			
		||||
 | 
			
		||||
    utils.bindShortcut('ctrl+r', utils.reloadApp);
 | 
			
		||||
 | 
			
		||||
    $(document).bind('keydown', 'ctrl+shift+i', () => {
 | 
			
		||||
    $("#open-dev-tools-button").toggle(utils.isElectron());
 | 
			
		||||
 | 
			
		||||
    if (utils.isElectron()) {
 | 
			
		||||
        const openDevTools = () => {
 | 
			
		||||
            require('electron').remote.getCurrentWindow().toggleDevTools();
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        utils.bindShortcut('ctrl+shift+i', openDevTools);
 | 
			
		||||
        $("#open-dev-tools-button").click(openDevTools);
 | 
			
		||||
    }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function openInPageSearch() {
 | 
			
		||||
        if (utils.isElectron()) {
 | 
			
		||||
@@ -117,10 +136,6 @@ function registerEntrypoints() {
 | 
			
		||||
 | 
			
		||||
    utils.bindShortcut('ctrl+f', openInPageSearch);
 | 
			
		||||
 | 
			
		||||
    if (utils.isMac()) {
 | 
			
		||||
        utils.bindShortcut('meta+f', openInPageSearch);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // FIXME: do we really need these at this point?
 | 
			
		||||
    utils.bindShortcut("ctrl+shift+up", () => {
 | 
			
		||||
        const node = treeService.getCurrentNode();
 | 
			
		||||
@@ -139,13 +154,11 @@ function registerEntrypoints() {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (utils.isElectron()) {
 | 
			
		||||
        $(document).bind('keydown', 'ctrl+-', zoomService.decreaseZoomFactor);
 | 
			
		||||
        $(document).bind('keydown', 'ctrl+=', zoomService.increaseZoomFactor);
 | 
			
		||||
        utils.bindShortcut('ctrl+-', zoomService.decreaseZoomFactor);
 | 
			
		||||
        utils.bindShortcut('ctrl+=', zoomService.increaseZoomFactor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $("#note-title").bind('keydown', 'return', () => $("#note-detail-text").focus());
 | 
			
		||||
 | 
			
		||||
    $("#upload-file-button").click(fileService.uploadFile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
import treeService from './tree.js';
 | 
			
		||||
import protectedSessionHolder from './protected_session_holder.js';
 | 
			
		||||
import utils from './utils.js';
 | 
			
		||||
import server from './server.js';
 | 
			
		||||
 | 
			
		||||
function exportBranch(branchId, type, format) {
 | 
			
		||||
    const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}?protectedSessionId=` + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
 | 
			
		||||
 | 
			
		||||
    console.log(url);
 | 
			
		||||
 | 
			
		||||
    utils.download(url);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let importNoteId;
 | 
			
		||||
 | 
			
		||||
function importIntoNote(noteId) {
 | 
			
		||||
    importNoteId = noteId;
 | 
			
		||||
 | 
			
		||||
    $("#import-upload").trigger('click');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$("#import-upload").change(async function() {
 | 
			
		||||
    const formData = new FormData();
 | 
			
		||||
    formData.append('upload', this.files[0]);
 | 
			
		||||
 | 
			
		||||
    await $.ajax({
 | 
			
		||||
        url: baseApiUrl + 'notes/' + importNoteId + '/import',
 | 
			
		||||
        headers: server.getHeaders(),
 | 
			
		||||
        data: formData,
 | 
			
		||||
        dataType: 'json',
 | 
			
		||||
        type: 'POST',
 | 
			
		||||
        contentType: false, // NEEDED, DON'T REMOVE THIS
 | 
			
		||||
        processData: false, // NEEDED, DON'T REMOVE THIS
 | 
			
		||||
    })
 | 
			
		||||
        .fail((xhr, status, error) => alert('Import error: ' + xhr.responseText))
 | 
			
		||||
        .done(async note => {
 | 
			
		||||
            await treeService.reload();
 | 
			
		||||
 | 
			
		||||
            if (note) {
 | 
			
		||||
                const node = await treeService.activateNote(note.noteId);
 | 
			
		||||
 | 
			
		||||
                node.setExpanded(true);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    exportBranch,
 | 
			
		||||
    importIntoNote
 | 
			
		||||
};
 | 
			
		||||
@@ -1,29 +0,0 @@
 | 
			
		||||
import noteDetailService from "./note_detail.js";
 | 
			
		||||
import treeService from "./tree.js";
 | 
			
		||||
import server from "./server.js";
 | 
			
		||||
 | 
			
		||||
function uploadFile() {
 | 
			
		||||
    $("#file-upload").trigger('click');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$("#file-upload").change(async function() {
 | 
			
		||||
    const formData = new FormData();
 | 
			
		||||
    formData.append('upload', this.files[0]);
 | 
			
		||||
 | 
			
		||||
    const resp = await $.ajax({
 | 
			
		||||
        url: baseApiUrl + 'notes/' + noteDetailService.getCurrentNoteId() + '/upload',
 | 
			
		||||
        headers: server.getHeaders(),
 | 
			
		||||
        data: formData,
 | 
			
		||||
        type: 'POST',
 | 
			
		||||
        contentType: false, // NEEDED, DON'T OMIT THIS
 | 
			
		||||
        processData: false, // NEEDED, DON'T OMIT THIS
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    await treeService.reload();
 | 
			
		||||
 | 
			
		||||
    await treeService.activateNote(resp.noteId);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    uploadFile
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,8 @@ import linkService from './link.js';
 | 
			
		||||
import treeCache from './tree_cache.js';
 | 
			
		||||
import noteDetailService from './note_detail.js';
 | 
			
		||||
import noteTypeService from './note_type.js';
 | 
			
		||||
import noteTooltipService from './note_tooltip.js';
 | 
			
		||||
import protectedSessionService from'./protected_session.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the main frontend API interface for scripts. It's published in the local "api" object.
 | 
			
		||||
@@ -41,7 +43,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
    this.activateNewNote = async notePath => {
 | 
			
		||||
        await treeService.reload();
 | 
			
		||||
 | 
			
		||||
        await treeService.activateNote(notePath, true);
 | 
			
		||||
        await treeService.activateNote(notePath, noteDetailService.focusAndSelectTitle);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -198,9 +200,28 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @returns {string} content of currently loaded note in the editor (HTML, code etc.)
 | 
			
		||||
     * @returns {string} content of active note (loaded into right pane)
 | 
			
		||||
     */
 | 
			
		||||
    this.getCurrentNoteContent = noteDetailService.getCurrentNoteContent;
 | 
			
		||||
    this.getActiveNoteContent = noteDetailService.getCurrentNoteContent;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @returns {NoteFull} active note (loaded into right pane)
 | 
			
		||||
     */
 | 
			
		||||
    this.getActiveNote = noteDetailService.getCurrentNote;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This method checks whether user navigated away from the note from which the scripts has been started.
 | 
			
		||||
     * This is necessary because script execution is async and by the time it is finished, the user might have
 | 
			
		||||
     * already navigated away from this page - the end result would be that script might return data for the wrong
 | 
			
		||||
     * note.
 | 
			
		||||
     *
 | 
			
		||||
     * @method
 | 
			
		||||
     * @return {boolean} returns true if the original note is still loaded, false if user switched to another
 | 
			
		||||
     */
 | 
			
		||||
    this.isNoteStillActive = () => {
 | 
			
		||||
        return this.originEntity.noteId === noteDetailService.getCurrentNoteId();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
@@ -225,6 +246,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
 | 
			
		||||
     * @param {array} types - list of mime types to be used
 | 
			
		||||
     */
 | 
			
		||||
    this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     * @param {object} $el - jquery object on which to setup the tooltip
 | 
			
		||||
     */
 | 
			
		||||
    this.setupElementTooltip = noteTooltipService.setupElementTooltip;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @method
 | 
			
		||||
     */
 | 
			
		||||
    this.protectActiveNote = protectedSessionService.protectNoteAndSendToServer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default FrontendScriptApi;
 | 
			
		||||
							
								
								
									
										33
									
								
								src/public/javascripts/services/hoisted_note.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/public/javascripts/services/hoisted_note.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
import optionsInit from './options_init.js';
 | 
			
		||||
import server from "./server.js";
 | 
			
		||||
import tree from "./tree.js";
 | 
			
		||||
 | 
			
		||||
let hoistedNoteId;
 | 
			
		||||
 | 
			
		||||
optionsInit.optionsReady.then(options => {
 | 
			
		||||
    hoistedNoteId = options['hoistedNoteId'];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function getHoistedNoteId() {
 | 
			
		||||
    await optionsInit.optionsReady;
 | 
			
		||||
 | 
			
		||||
    return hoistedNoteId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function setHoistedNoteId(noteId) {
 | 
			
		||||
    hoistedNoteId = noteId;
 | 
			
		||||
 | 
			
		||||
    await server.put('options/hoistedNoteId/' + noteId);
 | 
			
		||||
 | 
			
		||||
    await tree.reload();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function unhoist() {
 | 
			
		||||
    await setHoistedNoteId('root');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    getHoistedNoteId,
 | 
			
		||||
    setHoistedNoteId,
 | 
			
		||||
    unhoist
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
import cssLoader from './css_loader.js';
 | 
			
		||||
 | 
			
		||||
const CKEDITOR = {"js": ["libraries/ckeditor/ckeditor.js"]};
 | 
			
		||||
 | 
			
		||||
const CODE_MIRROR = {
 | 
			
		||||
@@ -34,7 +36,7 @@ const RELATION_MAP = {
 | 
			
		||||
 | 
			
		||||
async function requireLibrary(library) {
 | 
			
		||||
    if (library.css) {
 | 
			
		||||
        library.css.map(cssUrl => requireCss(cssUrl));
 | 
			
		||||
        library.css.map(cssUrl => cssLoader.requireCss(cssUrl));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (library.js) {
 | 
			
		||||
@@ -59,16 +61,6 @@ async function requireScript(url) {
 | 
			
		||||
    await loadedScriptPromises[url];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function requireCss(url) {
 | 
			
		||||
    const css = Array
 | 
			
		||||
        .from(document.querySelectorAll('link'))
 | 
			
		||||
        .map(scr => scr.href);
 | 
			
		||||
 | 
			
		||||
    if (!css.includes(url)) {
 | 
			
		||||
        $('head').append($('<link rel="stylesheet" type="text/css" />').attr('href', url));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    requireLibrary,
 | 
			
		||||
    CKEDITOR,
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,8 @@ function addTextToEditor(text) {
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ko.bindingHandlers.noteLink = {
 | 
			
		||||
function init() {
 | 
			
		||||
    ko.bindingHandlers.noteLink = {
 | 
			
		||||
        init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) {
 | 
			
		||||
            const noteId = ko.unwrap(valueAccessor());
 | 
			
		||||
 | 
			
		||||
@@ -98,13 +99,15 @@ ko.bindingHandlers.noteLink = {
 | 
			
		||||
                $(element).append(link);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
};
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
 | 
			
		||||
// of opening the link in new window/tab
 | 
			
		||||
$(document).on('click', "a[data-action='note']", goToLink);
 | 
			
		||||
$(document).on('click', 'div.popover-content a, div.ui-tooltip-content a', goToLink);
 | 
			
		||||
$(document).on('dblclick', '#note-detail-text a', goToLink);
 | 
			
		||||
$(document).on('click', '#note-detail-text.ck-read-only a', goToLink);
 | 
			
		||||
$(document).on('click', 'span.ck-button__label', e => {
 | 
			
		||||
    // this is a link preview dialog from CKEditor link editing
 | 
			
		||||
    // for some reason clicked element is span
 | 
			
		||||
@@ -124,5 +127,6 @@ export default {
 | 
			
		||||
    getNotePathFromUrl,
 | 
			
		||||
    createNoteLink,
 | 
			
		||||
    addLinkToEditor,
 | 
			
		||||
    addTextToEditor
 | 
			
		||||
    addTextToEditor,
 | 
			
		||||
    init
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										25
									
								
								src/public/javascripts/services/mac_init.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/public/javascripts/services/mac_init.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Mac specific initialization
 | 
			
		||||
 */
 | 
			
		||||
import utils from "./utils.js";
 | 
			
		||||
 | 
			
		||||
function init() {
 | 
			
		||||
    if (utils.isElectron() && utils.isMac()) {
 | 
			
		||||
        utils.bindShortcut('meta+c', () => exec("copy"));
 | 
			
		||||
        utils.bindShortcut('meta+v', () => exec('paste'));
 | 
			
		||||
        utils.bindShortcut('meta+x', () => exec('cut'));
 | 
			
		||||
        utils.bindShortcut('meta+a', () => exec('selectAll'));
 | 
			
		||||
        utils.bindShortcut('meta+z', () => exec('undo'));
 | 
			
		||||
        utils.bindShortcut('meta+y', () => exec('redo'));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function exec(cmd) {
 | 
			
		||||
    document.execCommand(cmd);
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    init
 | 
			
		||||
}
 | 
			
		||||
@@ -38,7 +38,7 @@ function handleMessage(event) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (message.type === 'sync') {
 | 
			
		||||
        lastPingTs = new Date().getTime();
 | 
			
		||||
        lastPingTs = Date.now();
 | 
			
		||||
 | 
			
		||||
        if (message.data.length > 0) {
 | 
			
		||||
            console.debug(utils.now(), "Sync data: ", message.data);
 | 
			
		||||
@@ -81,10 +81,10 @@ setTimeout(() => {
 | 
			
		||||
    ws = connectWebSocket();
 | 
			
		||||
 | 
			
		||||
    lastSyncId = glob.maxSyncIdAtLoad;
 | 
			
		||||
    lastPingTs = new Date().getTime();
 | 
			
		||||
    lastPingTs = Date.now();
 | 
			
		||||
 | 
			
		||||
    setInterval(async () => {
 | 
			
		||||
        if (new Date().getTime() - lastPingTs > 30000) {
 | 
			
		||||
        if (Date.now() - lastPingTs > 30000) {
 | 
			
		||||
            console.log("Lost connection to server");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user