Compare commits

..

153 Commits

Author SHA1 Message Date
zadam 24c8b39d8e release 0.30.5 2019-03-12 22:21:35 +01:00
zadam 0144dc12df current note as in note loaded into right pane is now called "active note" in frontend API 2019-03-12 21:52:19 +01:00
zadam 65684550a8 updated API docs 2019-03-12 21:42:27 +01:00
zadam 6d09931a39 add getCurrentNote() frontend API, #444 2019-03-12 21:39:35 +01:00
zadam 37d2a7939c fix background/border on quick help dialog, closes #440 2019-03-09 18:57:21 +01:00
zadam a432ad7483 fix isProtected consistency for images and files + related consistency check 2019-03-08 22:25:12 +01:00
zadam ae17e4dc60 release 0.30.4 2019-03-07 22:40:05 +01:00
zadam 02eddc347a fix export of protected notes to tar archive, fixes #432 2019-03-07 22:00:23 +01:00
zadam ee58bf3d5c fix bundle execution error handling 2019-03-07 20:51:55 +01:00
zadam ecbaffa5f3 return focus back to note detail after quitting add link dialog 2019-03-07 20:45:32 +01:00
zadam fe86c09f22 make sure date label is always created with YYYY-MM-DD and not the rest of date time 2019-03-05 20:49:39 +01:00
zadam c8e01d6cce pretty print JSON into note content 2019-03-05 20:44:50 +01:00
zadam 7c404f03db unused param 2019-03-04 22:18:27 +01:00
zadam ed1cf6aad5 fix passing of startNote and originEntity to backend script API 2019-03-04 21:17:34 +01:00
zadam 9703fd61e2 protected note's shield background now looks better on the dark themes 2019-03-04 20:53:57 +01:00
zadam 16790e388b recent changes should show titles of protected notes correctly when in protected session 2019-03-04 20:44:20 +01:00
zadam b48474998b release 0.30.3-beta 2019-03-03 20:47:50 +01:00
zadam 95d8f07458 debugging info for image shrinking 2019-03-03 20:41:03 +01:00
zadam e628c30c89 fix OPML export to include correct OPML version 2019-03-03 19:43:30 +01:00
zadam 52a8aae74f moved test enex files to separate repo 2019-03-03 19:40:47 +01:00
zadam 54b5898582 detect mime types from the filename instead of relying on upload mime type 2019-03-03 00:25:31 +01:00
zadam 64974d75d5 added sync fill for note_contents 2019-03-02 19:59:32 +01:00
zadam bd118027fb note content is also part of hash check 2019-03-02 12:40:46 +01:00
zadam 36de217835 release 0.30.2-beta 2019-02-28 22:33:33 +01:00
zadam b5283d58bb nicer underlining under tooltip items 2019-02-28 22:32:54 +01:00
zadam 8414d97ffa improve logging a little bit 2019-02-27 22:15:52 +01:00
zadam 9f30d4e673 fix image caption editing (#422) 2019-02-26 22:59:38 +01:00
zadam 8e0d1fa0df better contrast of links on the dark theme 2019-02-26 22:51:33 +01:00
zadam 5b251b9977 added drag & drop files on note detail 2019-02-26 21:37:15 +01:00
zadam 8b3e721028 added "explodeArchives" option to the import dialog 2019-02-25 22:38:48 +01:00
zadam 7e2a2baa5d drag & drop now uses import code 2019-02-25 22:28:15 +01:00
zadam 003eed368b unify markdown mime to text/x-markdown 2019-02-25 21:57:11 +01:00
zadam 4b1cf05c0e import images 2019-02-25 21:22:57 +01:00
zadam d9429c4f4b import plain text file as text/html 2019-02-24 13:10:47 +01:00
zadam b7bd94b6b0 switchable image shrinking 2019-02-24 12:25:34 +01:00
zadam 51bbc10744 switchable image shrinking 2019-02-24 12:24:28 +01:00
zadam fb5df33ee7 new import options in the dialog, tooltips 2019-02-24 11:36:01 +01:00
zadam d8ba0ccd7d use formdata to pass text arguments during import instead of request path 2019-02-24 09:56:00 +01:00
zadam 886ea6c68c allow import of multiple files at the same time 2019-02-24 09:34:50 +01:00
zadam 936f85c09e drag & drop multi file upload to note tree 2019-02-23 20:33:27 +01:00
zadam b25deea21d fixes for relative paths 2019-02-22 23:03:20 +01:00
zadam cf5ec44303 another fix for debian package upload 2019-02-20 23:22:04 +01:00
zadam 6f956c2415 release 0.30.1-beta 2019-02-20 23:08:36 +01:00
zadam 3533160bef fix initial document setup 2019-02-20 23:07:57 +01:00
zadam 60cbfdcabd update API docs 2019-02-20 22:24:51 +01:00
zadam 604f036a54 fix debian package upload 2019-02-20 22:10:19 +01:00
zadam dd4f3ec264 release 0.30.0-beta 2019-02-20 21:58:31 +01:00
zadam ff67b8a0ba initial debian package support 2019-02-20 21:58:23 +01:00
zadam 1d5fb0b646 add possibility to create week note, closes #416 2019-02-19 22:49:57 +01:00
zadam 80931a318f exposing APIs to get month and year note, #416 2019-02-19 21:29:41 +01:00
zadam 16f16cb36a fixed API for Trilium Sender, closes #415 2019-02-19 21:24:35 +01:00
zadam 899f24cde5 minor node upgrades 2019-02-17 22:56:33 +01:00
zadam 9f29521ab8 disable caching of note autocomplete for more accurate results 2019-02-17 20:59:52 +01:00
zadam c1ce0c6b22 avoid various HTTP server issues with slashes by putting notePath into the body with POST 2019-02-17 20:49:51 +01:00
zadam a7fce33750 OPML v2 export 2019-02-16 23:58:42 +01:00
zadam 6fd8e73150 UI for export of OPML v2, WIP 2019-02-16 23:33:40 +01:00
zadam 1359dd86c2 OPML 2 import, closes #298, #286 2019-02-16 22:13:29 +01:00
zadam a1b610fc50 full screen help dialog 2019-02-16 19:42:58 +01:00
zadam c849d719e9 styling for external links 2019-02-16 18:49:57 +01:00
zadam 96de2e7008 fixed saved search 2019-02-15 21:21:26 +01:00
zadam f140b77e7c fix migration script 2019-02-15 21:10:00 +01:00
zadam 22228de63b sync changes for note content 2019-02-15 00:15:09 +01:00
zadam b0596c9eb2 removed noteId display in the note detail, #408 2019-02-14 20:57:56 +01:00
zadam 2a2319d434 created note info dialog, closes #408 2019-02-14 20:56:33 +01:00
zadam dad47d115f fixes for SQL console schema view 2019-02-13 23:27:00 +01:00
zadam 502026359c help page, closes #273 2019-02-13 23:06:11 +01:00
zadam 47b0e4e4d3 Save electron window size and position, closes #186 2019-02-12 22:42:40 +01:00
zadam 6c927d9159 Merge remote-tracking branch 'origin/note-content' 2019-02-12 21:14:42 +01:00
zadam ddc79b2517 release 0.29.1 2019-02-12 20:30:07 +01:00
zadam 4c2e12d2cb upgrade to bootstrap 4.3.0 2019-02-12 20:26:28 +01:00
zadam 14f7a8b7b9 safe import implementation 2019-02-11 23:45:58 +01:00
zadam caa7dd9619 prettier progress count 2019-02-10 22:56:14 +01:00
zadam 8aa7e2d0a0 fixes in opml export and note content loading 2019-02-10 22:45:44 +01:00
zadam 6be8a3f343 added progress also to export 2019-02-10 22:30:55 +01:00
zadam a097cefba7 import error handling 2019-02-10 19:53:57 +01:00
zadam e4c78f3887 added ImportContext 2019-02-10 19:36:03 +01:00
zadam 5baa251944 more changes to import reporting through WS 2019-02-10 16:59:50 +01:00
zadam cde68abec9 progress of tar import through WS 2019-02-10 16:36:25 +01:00
zadam 51175e3676 import/export refactorign 2019-02-10 15:33:56 +01:00
zadam 45ddfef30a new import dialog 2019-02-10 14:33:13 +01:00
zadam 1e1d78999e some help dialog content 2019-02-10 12:19:48 +01:00
zadam 92fcd7b345 sql console added to global menu and now has schema info 2019-02-10 10:38:18 +01:00
zadam e04f1cd574 help button with no help dialog yet 2019-02-09 19:48:19 +01:00
zadam 176c3a5d51 added dev tools to global menu 2019-02-09 19:25:55 +01:00
zadam c09570cf39 global menu 2019-02-09 19:17:16 +01:00
zadam 4a093000be note content refactoring, WIP 2019-02-08 21:01:26 +01:00
zadam 6952b643ae note content refactoring, WIP 2019-02-07 22:16:40 +01:00
zadam c487a95bc7 note content refactoring, WIP 2019-02-06 21:29:23 +01:00
zadam 8884177d9f split out note's content into separate entity, WIP 2019-02-06 20:19:25 +01:00
zadam 8b250ed523 fix upload of the same file in succession, #388 2019-02-03 17:44:06 +01:00
zadam d8b78d8025 check reference issues only for non deleted entities 2019-02-03 16:27:26 +01:00
zadam 42112b8053 fix consistency check 2019-02-03 16:22:45 +01:00
zadam 6cc0dd5a80 release 0.29.0-beta 2019-02-03 15:44:19 +01:00
zadam afd5f4823f added Steel Blue theme to demo document 2019-02-03 15:39:27 +01:00
zadam b0cf82c91b fix 2019-02-03 15:37:01 +01:00
zadam 6a67cdd5af appThemeClass is redundant 2019-02-03 15:35:37 +01:00
zadam bad7b84993 error handling in custom request handler 2019-02-03 11:15:32 +01:00
zadam d3ca6b5ae6 styling for scrollbar which looks ugly otherwise in dark themes 2019-02-03 10:21:28 +01:00
zadam da5009f089 main border color CSS variable 2019-02-03 10:09:59 +01:00
zadam c08524c977 fix CSS class of user theme 2019-02-03 00:12:57 +01:00
zadam f89537037e small styling fixes 2019-02-02 23:51:00 +01:00
zadam c153793766 added CSS variable for disabled button background 2019-02-02 23:26:39 +01:00
zadam 0aec5927d5 added missing labels customRequestHandler, customResourceProvider to autocomplete 2019-02-02 22:33:02 +01:00
zadam 8aea9a1801 added font family CSS variables to theming API 2019-02-02 20:45:38 +01:00
zadam 73247e3220 minor library updates 2019-02-02 19:21:30 +01:00
zadam 89344a6eda final fixes and refactorings for consistency checks 2019-02-02 12:41:20 +01:00
zadam 40d2e6ea83 refactoring consistency checks WIP 2019-02-02 11:26:27 +01:00
zadam 910cfe9a17 refactoring consistency checks WIP 2019-02-02 10:38:33 +01:00
zadam e58a80fc00 consistency checks WIP 2019-02-02 09:26:57 +01:00
zadam 4a2319cb33 refactoring of consistency checks plus some autofixers 2019-02-01 22:48:51 +01:00
zadam 5619088c41 raise payload size limit to 500 MB #395 2019-01-29 21:19:08 +01:00
zadam 60271993eb Merge pull request #392 from jkurei/ios_favicon
Better icon for iOS' homescreen
2019-01-28 23:01:12 +01:00
jkurei 6695e8b011 Better icon for iOS' homescreen 2019-01-28 22:48:01 +01:00
zadam 707df18b93 added type and mime classes on body as well #383 2019-01-28 21:42:37 +01:00
zadam 90895f1288 added noteId to file view 2019-01-27 23:10:37 +01:00
zadam ba1ca506af change in referencing CSS resources to allow easier relative linking 2019-01-27 22:34:41 +01:00
zadam f90ed99a40 fix leaf node having angle bracket in dark & black themes, closes #387 2019-01-27 21:54:24 +01:00
zadam 67630b1a22 options now allow selecting user theme 2019-01-27 21:18:11 +01:00
zadam 2c1580ea65 appCss/appTheme are now loaded as external CSS files instead of inline styles 2019-01-27 17:01:37 +01:00
zadam 840a0b5f64 custom handler refactoring 2019-01-27 16:37:18 +01:00
zadam b39f6ef7ad bug fixes for custom handlers 2019-01-27 15:47:40 +01:00
zadam fb27088fcd smaller children overview font 2019-01-27 14:26:39 +01:00
azivner 76fbff68ba added readOnly attribute which puts text editor into readonly mode #371 2019-01-27 13:10:03 +01:00
azivner 54de4d236d custom HTTP handler which triggers associated script notes WIP, #356 2019-01-27 12:28:20 +01:00
azivner e211dd65ad exit on detection of not supported node version, #324 2019-01-26 19:59:51 +01:00
azivner a87f4d8653 search can be triggered from URL, closes #385 2019-01-25 22:18:34 +01:00
azivner b59c175c2e add HTML header with UTF-8 meta encoding declaration to exported HTML files, fixes #384 2019-01-25 21:34:14 +01:00
azivner 580104c4c5 using trilium's confirm dialog, small refactoring 2019-01-24 22:18:31 +01:00
zadam 0fc3053b0a Merge pull request #377 from flurmbo/master
add confirm type change dialog when note not empty
2019-01-24 22:12:09 +01:00
Phil Marshall 929e0f69c2 add confirm type change dialog when note not empty 2019-01-23 15:15:24 -06:00
azivner e70af1300a drag and drop moves multiple items only if CTRL is pressed, active note has now bold text for more differentiation from selected note 2019-01-23 21:13:04 +01:00
azivner 4d0e46021b Mac uses CMD+Left, CMD+Right for history navigation, closes #376 2019-01-23 20:15:33 +01:00
azivner 1a9a49b739 release 0.28.3 2019-01-22 23:01:32 +01:00
azivner 2ac560c56e text note should change its icon after having new note inserted into, fixes #361 2019-01-22 21:21:44 +01:00
azivner c23387c0fb make search dialog more responsive in narrow sidebar, fixes #367 2019-01-22 20:54:00 +01:00
azivner 0ff250fe15 font sizes were not created for new documents - fix plus migration for existing ones 2019-01-22 20:34:45 +01:00
azivner 52b1e58b26 make tree selection more visually consistent 2019-01-22 20:23:54 +01:00
azivner 484715e440 fix icon in desktop linux build, fixes #372 2019-01-22 19:49:33 +01:00
azivner 9d42c3d802 release 0.28.2 2019-01-21 22:55:12 +01:00
azivner c654172d33 auto fixer for "undeleted branch of deleted note" consistency check 2019-01-21 22:51:49 +01:00
azivner e17b26c883 revert consistency checks refactoring for now 2019-01-21 22:46:27 +01:00
azivner 24d02d9cf5 fix in task manager script to not error out so much on deletion 2019-01-21 22:05:37 +01:00
azivner 7208a311ac check that note is not deleted before creating a branch 2019-01-21 21:55:40 +01:00
azivner ad7355372b issue template 2019-01-21 19:55:07 +01:00
azivner f18b5babad uncommented issue template 2019-01-20 16:47:49 +01:00
azivner 9831ec0ca9 added issue template 2019-01-20 16:46:56 +01:00
azivner 596544eca3 fix setNoteToParent API method, closes #360 2019-01-20 16:33:09 +01:00
azivner 1f853024ee more autofixers WIP 2019-01-19 09:57:51 +01:00
azivner 0308b13460 expose app info on the backend script api #345 2019-01-18 23:57:08 +01:00
azivner 06b8a82f70 refactoring of consistency checks + some auto fixers 2019-01-18 19:32:59 +01:00
azivner 91ca07929d before we clone the note we must make sure it's not deleted 2019-01-17 23:24:59 +01:00
azivner afabaa5fdb workaround for hidden last line on mobile 2019-01-17 21:13:53 +01:00
azivner a6fd3fa77c release 0.28.1-beta 2019-01-17 00:03:17 +01:00
189 changed files with 8318 additions and 30291 deletions
+221 -145
View File
@@ -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>&quot;&quot;</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>&apos;&apos;</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>&quot;&quot;</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>&quot;&quot;</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>&apos;1970-01-01T00:00:00.000Z&apos;</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>&quot;&quot;</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>&quot;&quot;</DefaultExpression>
</column>
<column id="82" parent="11" name="dateCreated">
<Position>6</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
<DefaultExpression>&apos;2018-05-08T23:41:15.225Z&apos;</DefaultExpression>
</column>
<column id="83" parent="11" name="dateModified">
<Position>7</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
<DefaultExpression>&apos;2018-05-08T23:41:15.225Z&apos;</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>&apos;&apos;</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>&apos;&apos;</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>&quot;&quot;</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>&quot;note&quot;</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>&apos;text&apos;</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>&apos;text/html&apos;</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>&quot;&quot;</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>&quot;&quot;</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>&apos;1970-01-01T00:00:00.000Z&apos;</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>&quot;&quot;</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>
+7
View 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
+2
View File
@@ -11,6 +11,8 @@ cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
cp src/public/images/app-icons/png/128x128.png $BUILD_DIR/icon.png
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
+1 -1
View File
@@ -20,7 +20,7 @@ cp bin/deps/mac-x64/image/gifsicle node_modules/giflossy/vendor/
# Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
./reset-local.sh
./bin/reset-local.sh
echo "Zipping mac x64 electron distribution..."
+1 -1
View File
@@ -22,7 +22,7 @@ mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
./reset-local.sh
./bin/reset-local.sh
echo "Zipping windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
+3
View File
@@ -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
View 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" ]
}
Regular → Executable
View File
Regular → Executable
View File
+8
View File
@@ -43,6 +43,7 @@ git push origin $TAG
bin/build.sh
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
@@ -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 \
BIN
View File
Binary file not shown.
+11
View 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');
@@ -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;
@@ -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;
+23 -13
View File
@@ -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`)
);
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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
View 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"> &rarr; {Promise.&lt;<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.&lt;<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>
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -150,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">
+1 -1
View File
@@ -104,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">
+5 -2
View File
@@ -36,7 +36,10 @@ class Entity {
*/
constructor(row = {}) {
for (const key in row) {
this[key] = row[key];
// ! is used when joint-fetching notes and note_contents objects for performance
if (!key.startsWith('!')) {
this[key] = row[key];
}
}
if ('isDeleted' in this) {
@@ -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">
+1 -1
View File
@@ -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">
+74 -20
View File
@@ -30,6 +30,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');
@@ -40,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.
*
@@ -47,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
@@ -58,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
@@ -75,19 +77,64 @@ class Note extends Entity {
if (this.isProtected &amp;&amp; this.noteId) {
this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
protectedSessionService.decryptNote(this);
if (this.isContentAvailable) {
protectedSessionService.decryptNote(this);
}
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]";
}
}
this.setContent(this.content);
}
setContent(content) {
this.content = content;
/** @returns {Promise&lt;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);
}
if (this.isStringNote()) {
this.noteContent.content = this.noteContent.content.toString("UTF-8");
}
}
catch(e) {}
return this.noteContent;
}
/** @returns {Promise&lt;*>} */
async getContent() {
const noteContent = await this.getNoteContent();
return noteContent.content;
}
/** @returns {Promise&lt;*>} */
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 */
@@ -113,6 +160,13 @@ class Note extends Entity {
return (this.type === "code" || this.type === "file" || this.type === "render") &amp;&amp; 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() &amp;&amp; this.mime.endsWith('env=frontend'))) {
@@ -629,13 +683,6 @@ class Note extends Entity {
}
beforeSaving() {
if (this.isJson() &amp;&amp; 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;
}
@@ -654,12 +701,19 @@ class Note extends Entity {
// cannot be static!
updatePojo(pojo) {
if (pojo.isProtected) {
protectedSessionService.encryptNote(pojo);
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;
}
}
@@ -673,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">
@@ -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 &amp;&amp; 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&lt;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">
+1 -1
View File
@@ -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">
+3 -3
View File
@@ -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">
+1 -1
View File
@@ -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&lt;{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&lt;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&lt;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&lt;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&lt;Note|null>}
*/
this.getYearNote = dateNoteService.getYearNote;
/**
* @method
* @param {string} parentNoteId - this note's child notes will be sorted
@@ -261,7 +311,12 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
*
* @returns {Promise&lt;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>
@@ -274,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">
+422 -125
View File
@@ -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#line17">line 17</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#line23">line 23</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#line25">line 25</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#line21">line 21</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#line42">line 42</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#line34">line 34</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#line61">line 61</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#line198">line 198</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#line158">line 158</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"> &rarr; {<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"> &rarr; {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"> &rarr; {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#line222">line 222</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"> &rarr; {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#line204">line 204</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"> &rarr; {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#line216">line 216</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#line151">line 151</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#line143">line 143</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"> &rarr; {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#line210">line 210</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#line165">line 165</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#line189">line 189</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#line111">line 111</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,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#line228">line 228</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line248">line 248</a>
</li></ul></dd>
@@ -2657,7 +2954,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#line234">line 234</a>
<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>
@@ -2792,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#line181">line 181</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>
@@ -2927,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#line173">line 173</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>
+117 -59
View File
@@ -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>
@@ -198,64 +314,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>
+3 -1
View File
@@ -59,7 +59,9 @@
get toString() {
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
}
}</code></pre>
}
export default Attribute;</code></pre>
</article>
</section>
+6 -8
View File
@@ -36,15 +36,13 @@ class NoteFull extends NoteShort {
super(treeCache, row);
/** @param {string} */
this.content = row.content;
this.noteContent = row.noteContent;
if (this.content !== "" &amp;&amp; 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 -1
View File
@@ -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#line48">line 48</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>
@@ -35,6 +35,7 @@ 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.
@@ -70,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);
};
/**
@@ -227,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
@@ -259,7 +279,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
* @method
* @param {object} $el - jquery object on which to setup the tooltip
*/
this.setupElementTooltip = noteTooltipService.setupElementTooltip
this.setupElementTooltip = noteTooltipService.setupElementTooltip;
/**
* @method
*/
this.protectActiveNote = protectedSessionService.protectNoteAndSendToServer;
}
export default FrontendScriptApi;</code></pre>
+13 -3
View File
@@ -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);
+5
View 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
+2217 -795
View File
File diff suppressed because it is too large Load Diff
+28 -25
View File
@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.28.1-beta",
"version": "0.30.5",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -26,56 +26,59 @@
"body-parser": "1.18.3",
"cls-hooked": "4.2.2",
"commonmark": "0.28.1",
"cookie-parser": "1.4.3",
"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.7.0",
"file-type": "10.8.0",
"fs-extra": "7.0.1",
"get-port": "4.1.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.23.0",
"mime-types": "^2.1.22",
"moment": "2.24.0",
"multer": "1.4.1",
"node-abi": "2.5.1",
"node-abi": "2.7.1",
"open": "0.0.5",
"rand-token": "0.4.0",
"rcedit": "1.1.1",
"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": "18.12.21",
"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.1",
"electron-builder": "20.38.4",
"electron-compile": "6.4.3",
"electron-packager": "13.0.1",
"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": [
+3 -1
View File
@@ -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);
+4 -1
View File
@@ -8,7 +8,10 @@ class Entity {
*/
constructor(row = {}) {
for (const key in row) {
this[key] = row[key];
// ! is used when joint-fetching notes and note_contents objects for performance
if (!key.startsWith('!')) {
this[key] = row[key];
}
}
if ('isDeleted' in this) {
+5
View File
@@ -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,6 +13,7 @@ const ENTITY_NAME_TO_ENTITY = {
"attributes": Attribute,
"branches": Branch,
"notes": Note,
"note_contents": NoteContent,
"note_revisions": NoteRevision,
"recent_notes": RecentNote,
"options": Option,
@@ -48,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);
}
+54 -23
View File
@@ -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
@@ -54,26 +56,57 @@ class Note extends Entity {
// saving ciphertexts in case we do want to update protected note outside of protected session
// (which is allowed)
this.titleCipherText = this.title;
this.contentCipherText = this.content;
this.title = "[protected]";
this.content = "";
}
}
}
/** @returns {Promise<NoteContent>} */
async getNoteContent() {
if (!this.noteContent) {
this.noteContent = await repository.getEntity(`SELECT * FROM note_contents WHERE noteId = ?`, [this.noteId]);
if (!this.noteContent) {
throw new Error("Note content not found for noteId=" + this.noteId);
}
if (this.isStringNote()) {
this.noteContent.content = this.noteContent.content.toString("UTF-8");
}
}
this.setContent(this.content);
return this.noteContent;
}
setContent(content) {
this.content = content;
/** @returns {Promise<*>} */
async getContent() {
const noteContent = await this.getNoteContent();
// if parsing below is not successful then there's no jsonContent as opposed to still having the old unupdated ones
delete this.jsonContent;
return noteContent.content;
}
try {
this.jsonContent = JSON.parse(this.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();
}
catch(e) {}
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 */
@@ -99,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'))) {
@@ -615,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;
}
@@ -646,15 +679,13 @@ class Note extends Entity {
else {
// updating protected note outside of protected session means we will keep original ciphertexts
pojo.title = pojo.titleCipherText;
pojo.content = pojo.contentCipherText;
}
}
delete pojo.jsonContent;
delete pojo.isContentAvailable;
delete pojo.__attributeCache;
delete pojo.titleCipherText;
delete pojo.contentCipherText;
delete pojo.noteContent;
}
}
+96
View 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;
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+1 -1
View File
@@ -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

+25 -1
View File
@@ -8,11 +8,11 @@ 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 exportService from './services/export.js';
import link from './services/link.js';
import messagingService from './services/messaging.js';
import noteDetailService from './services/note_detail.js';
@@ -37,6 +37,7 @@ 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;
@@ -79,6 +80,10 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
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 => {
@@ -89,8 +94,19 @@ $(document).on("click", "button[data-help-page]", e => {
$("#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
@@ -119,8 +135,16 @@ $("#export-note-button").click(function () {
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();
@@ -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
};
+1 -1
View File
@@ -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) {
+68 -4
View File
@@ -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}?protectedSessionId=` + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
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
View File
@@ -0,0 +1,11 @@
const $dialog = $("#help-dialog");
async function showDialog() {
glob.activeDialog = $dialog;
$dialog.modal();
}
export default {
showDialog
}
+145
View 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
}
@@ -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));
}
+26 -2
View File
@@ -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");
@@ -50,7 +51,22 @@ addTabHandler((function() {
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()) {
@@ -71,12 +87,20 @@ addTabHandler((function() {
$themeSelect.change(function() {
const newTheme = $(this).val();
for (const clazz of $body[0].classList) {
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);
+30 -2
View File
@@ -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);
+6 -8
View File
@@ -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;
}
}
@@ -160,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
+1 -1
View File
@@ -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}`);
}
}
@@ -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,23 +33,34 @@ const dragAndDropSetup = {
return true;
},
dragEnter: (node, data) => true, // allow drop on any node
dragOver: (node, data) => true,
dragDrop: (node, data) => {
// This function MUST be defined to enable dropping of items on the tree.
// data.hitMode is 'before', 'after', or 'over'.
const dataTransfer = data.dataTransfer;
const selectedNodes = treeService.getSelectedNodes();
if (data.hitMode === "before") {
treeChangesService.moveBeforeNode(selectedNodes, node);
}
else if (data.hitMode === "after") {
treeChangesService.moveAfterNode(selectedNodes, node);
}
else if (data.hitMode === "over") {
treeChangesService.moveToNode(selectedNodes, node);
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 {
throw new Error("Unknown hitMode=" + data.hitMode);
// This function MUST be defined to enable dropping of items on the tree.
// data.hitMode is 'before', 'after', or 'over'.
const selectedNodes = treeService.getSelectedNodes();
if (data.hitMode === "before") {
treeChangesService.moveBeforeNode(selectedNodes, node);
} else if (data.hitMode === "after") {
treeChangesService.moveAfterNode(selectedNodes, node);
} else if (data.hitMode === "over") {
treeChangesService.moveToNode(selectedNodes, node);
} else {
throw new Error("Unknown hitMode=" + data.hitMode);
}
}
}
};
+26 -9
View File
@@ -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,15 +55,28 @@ 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);
utils.bindShortcut('alt+left', window.history.back);
utils.bindShortcut('alt+right', 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 => {
@@ -87,13 +101,18 @@ function registerEntrypoints() {
utils.bindShortcut('ctrl+r', utils.reloadApp);
utils.bindShortcut('ctrl+shift+i', () => {
if (utils.isElectron()) {
$("#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()) {
@@ -140,8 +159,6 @@ function registerEntrypoints() {
}
$("#note-title").bind('keydown', 'return', () => $("#note-detail-text").focus());
$("#upload-file-button").click(fileService.uploadFile);
}
export default {
-50
View File
@@ -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
};
-29
View File
@@ -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
}
@@ -200,9 +200,15 @@ 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.
@@ -213,7 +219,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
* @method
* @return {boolean} returns true if the original note is still loaded, false if user switched to another
*/
this.isNoteStillLoaded = () => {
this.isNoteStillActive = () => {
return this.originEntity.noteId === noteDetailService.getCurrentNoteId();
};
@@ -250,7 +256,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
/**
* @method
*/
this.protectCurrentNote = protectedSessionService.protectNoteAndSendToServer;
this.protectActiveNote = protectedSessionService.protectNoteAndSendToServer;
}
export default FrontendScriptApi;
@@ -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,
+1
View File
@@ -107,6 +107,7 @@ function init() {
$(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
+3 -3
View File
@@ -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");
}
@@ -92,7 +92,9 @@ function initNoteAutocomplete($el, options) {
suggestion: function(suggestion) {
return suggestion.highlighted;
}
}
},
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
cache: false
}
]);
+39 -14
View File
@@ -18,6 +18,7 @@ import noteDetailRelationMap from './note_detail_relation_map.js';
import bundleService from "./bundle.js";
import attributeService from "./attributes.js";
import utils from "./utils.js";
import importDialog from "../dialogs/import.js";
const $noteTitle = $("#note-title");
@@ -26,10 +27,10 @@ const $noteDetailComponents = $(".note-detail-component");
const $protectButton = $("#protect-button");
const $unprotectButton = $("#unprotect-button");
const $noteDetailWrapper = $("#note-detail-wrapper");
const $noteIdDisplay = $("#note-id-display");
const $childrenOverview = $("#children-overview");
const $scriptArea = $("#note-detail-script-area");
const $savedIndicator = $("#saved-indicator");
const $body = $("body");
let currentNote = null;
@@ -116,7 +117,10 @@ async function saveNote() {
}
note.title = $noteTitle.val();
note.content = getCurrentNoteContent(note);
if (note.noteContent != null) { // might be null for file/image
note.noteContent.content = getCurrentNoteContent(note);
}
// it's important to set the flag back to false immediatelly after retrieving title and content
// otherwise we might overwrite another change (especially async code)
@@ -145,12 +149,21 @@ async function saveNoteIfChanged() {
$savedIndicator.fadeIn();
}
function setNoteBackgroundIfProtected(note) {
$noteDetailWrapper.toggleClass("protected", note.isProtected);
$protectButton.toggleClass("active", note.isProtected);
$protectButton.prop("disabled", note.isProtected);
$unprotectButton.toggleClass("active", !note.isProtected);
$unprotectButton.prop("disabled", !note.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
function updateNoteView() {
$noteDetailWrapper.toggleClass("protected", currentNote.isProtected);
$protectButton.toggleClass("active", currentNote.isProtected);
$protectButton.prop("disabled", currentNote.isProtected);
$unprotectButton.toggleClass("active", !currentNote.isProtected);
$unprotectButton.prop("disabled", !currentNote.isProtected || !protectedSessionHolder.isProtectedSessionAvailable());
for (const clazz of Array.from($body[0].classList)) { // create copy to safely iterate over while removing classes
if (clazz.startsWith("type-") || clazz.startsWith("mime-")) {
$body.removeClass(clazz);
}
}
$body.addClass(utils.getNoteTypeClass(currentNote.type));
$body.addClass(utils.getMimeTypeClass(currentNote.mime));
}
async function handleProtectedSession() {
@@ -191,9 +204,7 @@ async function loadNoteDetail(noteId) {
attributeService.invalidateAttributes();
}
$noteIdDisplay.html(noteId);
setNoteBackgroundIfProtected(currentNote);
updateNoteView();
$noteDetailWrapper.show();
@@ -270,7 +281,7 @@ async function showChildrenOverview() {
text: await treeUtils.getNoteTitle(childBranch.noteId, childBranch.parentNoteId)
}).attr('data-action', 'note').attr('data-note-path', notePath + '/' + childBranch.noteId);
const childEl = $('<div class="child-overview">').html(link);
const childEl = $('<div class="child-overview-item">').html(link);
$childrenOverview.append(childEl);
}
@@ -323,6 +334,20 @@ messagingService.subscribeToSyncMessages(syncData => {
}
});
$noteDetailWrapper.on("dragover", e => e.preventDefault());
$noteDetailWrapper.on("dragleave", e => e.preventDefault());
$noteDetailWrapper.on("drop", e => {
importDialog.uploadFiles(getCurrentNoteId(), e.originalEvent.dataTransfer.files, {
safeImport: true,
shrinkImages: true,
textImportedAsText: true,
codeImportedAsCode: true,
explodeArchives: true
});
});
$(document).ready(() => {
$noteTitle.on('input', () => {
noteChanged();
@@ -344,9 +369,10 @@ setInterval(saveNoteIfChanged, 3000);
export default {
reload,
switchToNote,
setNoteBackgroundIfProtected,
updateNoteView,
loadNote,
getCurrentNote,
getCurrentNoteContent,
getCurrentNoteType,
getCurrentNoteId,
focusOnTitle,
@@ -354,7 +380,6 @@ export default {
saveNote,
saveNoteIfChanged,
noteChanged,
getCurrentNoteContent,
onNoteChange,
addDetailLoadedListener
};
@@ -49,7 +49,7 @@ async function show() {
// this needs to happen after the element is shown, otherwise the editor won't be refreshed
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
// we provide fallback
codeEditor.setValue(currentNote.content || "");
codeEditor.setValue(currentNote.noteContent.content || "");
const info = CodeMirror.findModeByMIME(currentNote.mime);
@@ -5,6 +5,7 @@ import noteDetailService from "./note_detail.js";
const $component = $('#note-detail-file');
const $fileNoteId = $("#file-note-id");
const $fileName = $("#file-filename");
const $fileType = $("#file-filetype");
const $fileSize = $("#file-filesize");
@@ -21,12 +22,18 @@ async function show() {
$component.show();
$fileNoteId.text(currentNote.noteId);
$fileName.text(attributeMap.originalFileName || "?");
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
$fileType.text(currentNote.mime);
$previewRow.toggle(!!currentNote.content);
$previewContent.text(currentNote.content);
if (currentNote.noteContent && currentNote.noteContent.content) {
$previewRow.show();
$previewContent.text(currentNote.noteContent.content);
}
else {
$previewRow.hide();
}
}
$downloadButton.click(() => utils.download(getFileUrl()));
@@ -26,7 +26,7 @@ async function show() {
$fileSize.text((attributeMap.fileSize || "?") + " bytes");
$fileType.text(currentNote.mime);
$imageView.prop("src", `/api/images/${currentNote.noteId}/${currentNote.title}`);
$imageView.prop("src", `api/images/${currentNote.noteId}/${currentNote.title}`);
}
$imageDownloadButton.click(() => utils.download(getFileUrl()));
@@ -93,9 +93,9 @@ function loadMapData() {
}
};
if (currentNote.content) {
if (currentNote.noteContent.content) {
try {
mapData = JSON.parse(currentNote.content);
mapData = JSON.parse(currentNote.noteContent.content);
} catch (e) {
console.log("Could not parse content: ", e);
}
@@ -6,17 +6,13 @@ const $searchString = $("#search-string");
const $component = $('#note-detail-search');
const $refreshButton = $('#note-detail-search-refresh-results-button');
function getContent() {
return JSON.stringify({
searchString: $searchString.val()
});
}
function show() {
$component.show();
console.log(noteDetailService.getCurrentNote());
try {
const json = JSON.parse(noteDetailService.getCurrentNote().content);
const json = JSON.parse(noteDetailService.getCurrentNote().noteContent.content);
$searchString.val(json.searchString);
}
@@ -28,6 +24,12 @@ function show() {
$searchString.on('input', noteDetailService.noteChanged);
}
function getContent() {
return JSON.stringify({
searchString: $searchString.val()
});
}
$refreshButton.click(async () => {
await noteDetailService.saveNoteIfChanged();
@@ -1,6 +1,7 @@
import libraryLoader from "./library_loader.js";
import noteDetailService from './note_detail.js';
import treeService from './tree.js';
import attributeService from "./attributes.js";
const $component = $('#note-detail-text');
@@ -19,7 +20,9 @@ async function show() {
}
}
textEditor.setData(noteDetailService.getCurrentNote().content);
textEditor.isReadOnly = await isReadOnly();
textEditor.setData(noteDetailService.getCurrentNote().noteContent.content);
$component.show();
}
@@ -36,6 +39,12 @@ function getContent() {
return content;
}
async function isReadOnly() {
const attributes = await attributeService.getAttributes();
return attributes.some(attr => attr.type === 'label' && attr.name === 'readOnly');
}
function focus() {
$component.focus();
}
@@ -111,18 +111,18 @@ async function renderTooltip(note, attributes) {
}
if (note.type === 'text') {
// surround with <div> for a case when note.content is pure text (e.g. "[protected]") which
// surround with <div> for a case when note's content is pure text (e.g. "[protected]") which
// then fails the jquery non-empty text test
content += '<div>' + note.content + '</div>';
content += '<div>' + note.noteContent.content + '</div>';
}
else if (note.type === 'code') {
content += $("<pre>")
.text(note.content)
.text(note.noteContent.content)
.prop('outerHTML');
}
else if (note.type === 'image') {
content += $("<img>")
.prop("src", `/api/images/${note.noteId}/${note.title}`)
.prop("src", `api/images/${note.noteId}/${note.title}`)
.prop('outerHTML');
}
// other types of notes don't have tooltip preview
+36 -7
View File
@@ -2,6 +2,7 @@ import treeService from './tree.js';
import noteDetailService from './note_detail.js';
import server from './server.js';
import infoService from "./info.js";
import confirmDialog from "../dialogs/confirm.js";
const $executeScriptButton = $("#execute-script-button");
const $toggleEditButton = $('#toggle-edit-button');
@@ -110,35 +111,63 @@ function NoteTypeModel() {
self.updateExecuteScriptButtonVisibility();
}
this.selectText = function() {
function confirmChangeIfContent() {
if (!noteDetailService.getCurrentNoteContent()) {
return true;
}
return confirmDialog.confirm("It is not recommended to change note type when note content is not empty. Do you want to continue anyway?");
}
this.selectText = async function() {
if (!await confirmChangeIfContent()) {
return;
}
self.type('text');
self.mime('');
self.mime('text/html');
save();
};
this.selectRender = function() {
this.selectRender = async function() {
if (!await confirmChangeIfContent()) {
return;
}
self.type('render');
self.mime('text/html');
save();
};
this.selectRelationMap = function() {
this.selectRelationMap = async function() {
if (!await confirmChangeIfContent()) {
return;
}
self.type('relation-map');
self.mime('application/json');
save();
};
this.selectCode = function() {
this.selectCode = async function() {
if (!await confirmChangeIfContent()) {
return;
}
self.type('code');
self.mime('');
self.mime('text/plain');
save();
};
this.selectCodeMime = function(el) {
this.selectCodeMime = async function(el) {
if (!await confirmChangeIfContent()) {
return;
}
self.type('code');
self.mime(el.mime);
@@ -125,7 +125,7 @@ async function protectNoteAndSendToServer() {
treeService.setProtected(note.noteId, note.isProtected);
noteDetailService.setNoteBackgroundIfProtected(note);
noteDetailService.updateNoteView();
}
async function unprotectNoteAndSendToServer() {
@@ -152,7 +152,7 @@ async function unprotectNoteAndSendToServer() {
treeService.setProtected(currentNote.noteId, currentNote.isProtected);
noteDetailService.setNoteBackgroundIfProtected(currentNote);
noteDetailService.updateNoteView();
}
async function protectSubtree(noteId, protect) {
@@ -8,7 +8,7 @@ let protectedSessionId = null;
optionsInitService.optionsReady.then(options => protectedSessionTimeout = options.protectedSessionTimeout);
setInterval(() => {
if (lastProtectedSessionOperationDate !== null && new Date().getTime() - lastProtectedSessionOperationDate.getTime() > protectedSessionTimeout * 1000) {
if (lastProtectedSessionOperationDate !== null && Date.now() - lastProtectedSessionOperationDate.getTime() > protectedSessionTimeout * 1000) {
resetProtectedSession();
}
}, 5000);
@@ -76,6 +76,15 @@ async function saveSearch() {
await treeService.activateNote(noteId);
}
function init() {
const hashValue = treeService.getHashValueFromAddress();
if (hashValue.startsWith("search=")) {
showSearch();
doSearch(hashValue.substr(7));
}
}
$searchInput.keyup(e => {
const searchText = $searchInput.val();
@@ -100,5 +109,6 @@ export default {
toggleSearch,
resetSearch,
showSearch,
doSearch
doSearch,
init
};
+20 -10
View File
@@ -331,7 +331,7 @@ function addRecentNote(branchId, notePath) {
setTimeout(async () => {
// we include the note into recent list only if the user stayed on the note at least 5 seconds
if (notePath && notePath === getCurrentNotePath()) {
await server.put('recent-notes/' + branchId + '/' + encodeURIComponent(notePath));
await server.post('recent-notes', { branchId, notePath });
}
}, 1500);
}
@@ -483,16 +483,20 @@ async function reload() {
await getTree().reload(notes);
}
function getNotePathFromAddress() {
return document.location.hash.substr(1); // strip initial #
function isNotePathInAddress() {
return getHashValueFromAddress().startsWith("root");
}
function getHashValueFromAddress() {
return document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
}
async function loadTree() {
const resp = await server.get('tree');
startNotePath = resp.startNotePath;
if (document.location.hash) {
startNotePath = getNotePathFromAddress();
if (isNotePathInAddress()) {
startNotePath = getHashValueFromAddress();
}
return await treeBuilder.prepareTree(resp.notes, resp.branches, resp.relations);
@@ -623,7 +627,10 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
await node.getLastChild().setActive(true);
const parentNoteEntity = await treeCache.getNote(node.data.noteId);
node.folder = true;
node.icon = await treeBuilder.getIcon(parentNoteEntity); // icon might change into folder
node.renderTitle();
}
else {
@@ -704,12 +711,14 @@ utils.bindShortcut('ctrl+p', createNoteInto);
utils.bindShortcut('ctrl+.', scrollToCurrentNote);
$(window).bind('hashchange', function() {
const notePath = getNotePathFromAddress();
if (isNotePathInAddress()) {
const notePath = getHashValueFromAddress();
if (notePath !== '-' && getCurrentNotePath() !== notePath) {
console.debug("Switching to " + notePath + " because of hash change");
if (notePath !== '-' && getCurrentNotePath() !== notePath) {
console.debug("Switching to " + notePath + " because of hash change");
activateNote(notePath);
activateNote(notePath);
}
}
});
@@ -742,5 +751,6 @@ export default {
showTree,
loadTree,
treeInitialized,
setExpandedToServer
setExpandedToServer,
getHashValueFromAddress
};
@@ -126,7 +126,9 @@ async function prepareRealBranch(parentNote) {
async function prepareSearchBranch(note) {
const fullNote = await noteDetailService.loadNote(note.noteId);
const results = (await server.get('search/' + encodeURIComponent(fullNote.jsonContent.searchString)))
const json = JSON.parse(fullNote.noteContent.content);
const results = (await server.get('search/' + encodeURIComponent(json.searchString)))
.filter(res => res.noteId !== note.noteId); // this is necessary because title of the search note is often the same as the search text which would match and create circle
// force to load all the notes at once instead of one by one
@@ -166,26 +168,15 @@ async function getExtraClasses(note) {
extraClasses.push(note.cssClass);
}
extraClasses.push(note.type);
extraClasses.push(utils.getNoteTypeClass(note.type));
if (note.mime) { // some notes should not have mime type (e.g. render)
extraClasses.push(getMimeTypeClass(note.mime));
extraClasses.push(utils.getMimeTypeClass(note.mime));
}
return extraClasses.join(" ");
}
function getMimeTypeClass(mime) {
const semicolonIdx = mime.indexOf(';');
if (semicolonIdx !== -1) {
// stripping everything following the semicolon
mime = mime.substr(0, semicolonIdx);
}
return 'mime-' + mime.toLowerCase().replace(/[\W_]+/g,"-");
}
export default {
prepareTree,
prepareBranch,
@@ -1,12 +1,12 @@
import treeService from './tree.js';
import cloningService from './cloning.js';
import exportService from './export.js';
import messagingService from './messaging.js';
import protectedSessionService from './protected_session.js';
import treeChangesService from './branches.js';
import treeUtils from './tree_utils.js';
import branchPrefixDialog from '../dialogs/branch_prefix.js';
import exportDialog from '../dialogs/export.js';
import importDialog from '../dialogs/import.js';
import infoService from "./info.js";
import treeCache from "./tree_cache.js";
import syncService from "./sync.js";
@@ -95,7 +95,7 @@ const contextMenuItems = [
{title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard"},
{title: "----"},
{title: "Export", cmd: "export", uiIcon: "arrow-up-right"},
{title: "Import into note (tar, opml, md, enex)", cmd: "importIntoNote", uiIcon: "arrow-down-left"},
{title: "Import into note", cmd: "importIntoNote", uiIcon: "arrow-down-left"},
{title: "----"},
{title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify"},
{title: "Force note sync", cmd: "forceNoteSync", uiIcon: "refresh"},
@@ -180,7 +180,7 @@ function selectContextMenuItem(event, cmd) {
exportDialog.showDialog("subtree");
}
else if (cmd === "importIntoNote") {
exportService.importIntoNote(node.data.noteId);
importDialog.showDialog();
}
else if (cmd === "collapseSubtree") {
treeService.collapseTree(node);
+20 -4
View File
@@ -45,7 +45,7 @@ function now() {
}
function isElectron() {
return window && window.process && window.process.type;
return !!(window && window.process && window.process.type);
}
function isMac() {
@@ -77,7 +77,7 @@ async function stopWatch(what, func) {
const ret = await func();
const tookMs = new Date().getTime() - start.getTime();
const tookMs = Date.now() - start.getTime();
console.log(`${what} took ${tookMs}ms`);
@@ -145,7 +145,6 @@ function bindShortcut(keyboardShortcut, handler) {
}
$(document).bind('keydown', keyboardShortcut, e => {
console.log(e);
handler();
e.preventDefault();
@@ -172,6 +171,21 @@ function setCookie(name, value) {
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getNoteTypeClass(type) {
return "type-" + type;
}
function getMimeTypeClass(mime) {
const semicolonIdx = mime.indexOf(';');
if (semicolonIdx !== -1) {
// stripping everything following the semicolon
mime = mime.substr(0, semicolonIdx);
}
return 'mime-' + mime.toLowerCase().replace(/[\W_]+/g,"-");
}
export default {
reloadApp,
parseDate,
@@ -198,5 +212,7 @@ export default {
bindShortcut,
isMobile,
isDesktop,
setCookie
setCookie,
getNoteTypeClass,
getMimeTypeClass
};
+1 -1
View File
@@ -91,7 +91,7 @@ function SetupModel() {
}
// not using server.js because it loads too many dependencies
const resp = await $.post('/api/setup/sync-from-server', {
const resp = await $.post('api/setup/sync-from-server', {
syncServerHost: syncServerHost,
syncProxy: syncProxy,
username: username,
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More