Compare commits

...

203 Commits

Author SHA1 Message Date
azivner
3b8d7b8fba release 0.27.3 2019-01-05 22:48:11 +01:00
azivner
9fca7f09a5 link to mobile frontend 2019-01-05 22:45:18 +01:00
azivner
fd39d6b3a9 using btn-secondary instead of btn-default since that doesn't exist in BS4 2019-01-05 21:51:27 +01:00
azivner
a103886ea5 responsive setup page 2019-01-05 21:49:40 +01:00
azivner
373408e401 fix Branch reference to parent note id after parent change 2019-01-05 19:25:22 +01:00
azivner
db44c1d8e6 border color tweaks 2019-01-05 11:49:17 +01:00
azivner
95a34c9e2d small tweaks of icon alignment 2019-01-05 11:41:09 +01:00
azivner
6ce401f260 release 0.27.2-beta 2019-01-04 23:33:32 +01:00
azivner
5d74dcd256 package-lock 2019-01-04 23:33:30 +01:00
azivner
5a9fc1697b electron 4.0.1 2019-01-04 23:32:14 +01:00
azivner
927415838c using enhanceTitle event instead of renderNode per https://github.com/mar10/fancytree/issues/927 2019-01-04 20:18:07 +01:00
azivner
d72fcefdc7 fix sync of deleted notes 2019-01-04 20:10:16 +01:00
azivner
0be173a8f7 lower lastSyncedPull if server max sync ID is lower 2019-01-04 18:58:46 +01:00
azivner
c3913a8735 updating the note cache after sync 2019-01-03 23:27:10 +01:00
azivner
e2dfe1b6de fixed setup page issues which caused wrong choice to be used in the wizard 2019-01-03 22:32:36 +01:00
azivner
fec3e47eb8 serialize binary note content into base64, incremented sync version 2019-01-03 22:13:58 +01:00
azivner
d72efd2450 removed unnecessary logging of data dir which is now logged as part of app info 2019-01-03 21:46:32 +01:00
azivner
ef1c840aa7 tiny fixes 2019-01-02 22:36:06 +01:00
azivner
1581464d8c fix layout - promoted attributes should never grow beyond its content 2019-01-02 20:21:34 +01:00
azivner
9de29584a4 added data directory to options -> about 2019-01-02 20:08:41 +01:00
azivner
9e2e6fb50c fixed glitch where "unhoist" button disappears after renaming the hoisted note 2019-01-02 19:26:01 +01:00
azivner
c85979b66b it should not be possible to add note after hoisted note 2019-01-02 18:59:08 +01:00
azivner
ecdc5865a6 release 0.27.1-beta 2019-01-01 20:54:23 +01:00
azivner
1771ddb787 responsive promoted attributes view and attribute overview to make sure note content is always visible. Fixes #262 2019-01-01 20:53:18 +01:00
azivner
3ab657fe46 created concept of "detail loaded listeners" which allow scripts to execute some action after the note detail has been loaded 2019-01-01 19:32:34 +01:00
azivner
8785dae753 force reload fancytree node when child is not found 2019-01-01 18:27:36 +01:00
azivner
2f1c5b29d4 update eslint 2019-01-01 18:06:52 +01:00
azivner
7135349a10 allow deleting protected notes outside of protected session 2019-01-01 17:04:21 +01:00
azivner
66c639d5e3 frontend API addition to protect current note 2019-01-01 15:39:13 +01:00
azivner
6704b755d8 attribute overview shows only owned attributes 2019-01-01 15:29:58 +01:00
azivner
cf96baad48 release 0.27.0-beta 2018-12-30 22:38:11 +01:00
azivner
32220476aa better behavior on default loading detail / switching between tree and detail 2018-12-30 22:36:39 +01:00
azivner
86bc84a2ad better detection of float parameter in label filters, fixes #265 2018-12-30 22:09:14 +01:00
azivner
de9e0c7929 lazy loading icon for both mobile and desktop 2018-12-30 21:13:35 +01:00
azivner
6963e662ef fix layout on chrome 2018-12-30 19:15:44 +01:00
azivner
7127822e8f placeholder for empty note content 2018-12-30 19:02:42 +01:00
azivner
0a35abf68f refresh note detail view after attribute save (from full dialog, not promoted notes), closes #261 2018-12-30 15:21:53 +01:00
azivner
3f8e8f8561 fix saving branch prefix, fixes #260 2018-12-29 10:35:44 +01:00
azivner
e02eca87b0 dont toggle panes note on the first load 2018-12-29 10:19:28 +01:00
azivner
2f680c4326 tweaks, fixes, refactorings, creating new note from detail, not tree 2018-12-29 10:04:59 +01:00
azivner
0b4a44a403 layout tweaks etc. 2018-12-29 09:13:52 +01:00
azivner
89299f865c api method to detect navigation away from current page 2018-12-29 08:40:35 +01:00
azivner
f6db9a50ab "switch to desktop version" button 2018-12-29 00:09:16 +01:00
azivner
78d9fac1e6 global actions context menu, logout 2018-12-28 23:57:11 +01:00
azivner
458ed1faff mobile detection 2018-12-28 23:47:06 +01:00
azivner
0657815de5 Merge branch 'master' into mobile 2018-12-28 22:31:51 +01:00
azivner
a608832681 change to relation map note type doesn't trigger content change, related issue #258 2018-12-28 22:31:06 +01:00
azivner
d2f72529b3 context menu with delete 2018-12-28 22:05:04 +01:00
azivner
28185af158 fix layout/scrolling issues in the tree 2018-12-28 20:36:18 +01:00
azivner
7aacd01ad7 separate css layout file for mobile and desktop 2018-12-28 19:47:02 +01:00
azivner
74cc34696e unifying expander icons in both desktop and mobile 2018-12-27 22:38:19 +01:00
azivner
d4baac0bb5 mobile fixes 2018-12-27 22:36:11 +01:00
azivner
35bc1421f1 cannot edit note title when not in protected session 2018-12-27 20:22:33 +01:00
azivner
d4db265fd9 non-modal protected session password form is now done separately as a kind of detail component. Also reworked branch prefix dialog input 2018-12-27 20:04:59 +01:00
azivner
1dad919de9 working protected session in mobile 2018-12-25 10:58:40 +01:00
azivner
246dfbdcb4 fix attribute loading for mobile 2018-12-24 23:08:43 +01:00
azivner
f8d32d64f5 content scrolling 2018-12-24 22:39:17 +01:00
azivner
5dea271d6f basic responsive layout 2018-12-24 20:38:38 +01:00
azivner
eeb62a6cf2 fix keyboard shortcut setup on mobile 2018-12-24 18:39:31 +01:00
azivner
35cf8026b0 activating note opens dialog with its detail 2018-12-24 12:49:27 +01:00
azivner
e0028ab6f1 mobile frontend WIP, removing extra dependencies 2018-12-24 10:10:36 +01:00
azivner
a32645cdeb fix scrolling to the top of detail after switching note 2018-12-24 09:47:00 +01:00
azivner
812f9f6fca initial work on mobile frontend 2018-12-23 22:28:57 +01:00
azivner
f7a670ec24 responsive login page 2018-12-23 11:06:11 +01:00
azivner
d0d24f0f4a unify ejs indentation to 4 spaces 2018-12-23 10:57:40 +01:00
azivner
042f9b7f2d fix positioning of protected session password dialog 2018-12-22 23:54:06 +01:00
azivner
2d260cdbed explicit node-abi required for 4.0.0 electron build 2018-12-22 23:10:03 +01:00
azivner
6a786cad83 updated API docs 2018-12-22 22:28:49 +01:00
azivner
67019b3d6c added attributes to frontend entity model 2018-12-22 22:16:32 +01:00
azivner
1db6e59077 tooltip related changes for scripting support 2018-12-22 20:57:09 +01:00
azivner
5e4770875e upgrade to bootstrap 4.2.1 2018-12-22 10:33:50 +01:00
azivner
e9a77f3f16 image sync fixes and 4.0.0 electron 2018-12-22 09:54:09 +01:00
azivner
cbec85f295 release 0.26.1 2018-12-20 19:54:09 +01:00
azivner
14bd5d301d fix broken image sync 2018-12-20 19:51:03 +01:00
azivner
321d0e8d64 explicit error handler for connection errors 2018-12-19 21:29:35 +01:00
azivner
84e1512031 added robots.txt to public root 2018-12-19 20:56:10 +01:00
azivner
b036852b2d release 0.26.0-beta 2018-12-18 22:49:48 +01:00
azivner
f693dc31e8 mention note hoisting in the readme 2018-12-18 20:50:03 +01:00
azivner
af8f5b11b8 better error handling in request 2018-12-18 20:39:56 +01:00
azivner
8ca943f87b fix hoistedNoteId option init 2018-12-18 20:34:24 +01:00
azivner
35cc9da626 note about system proxy in the settings 2018-12-17 22:58:53 +01:00
azivner
44cc86a1a5 added support for explicit proxy 2018-12-17 22:54:54 +01:00
azivner
7c3bbfd45e using http service for sync setup as well, removed request(-promise) dependency 2018-12-17 22:12:26 +01:00
azivner
a1f939e3a0 refactoring of network code into separate service 2018-12-17 21:34:02 +01:00
azivner
4ca7886090 uniform requests through electron's net and node http/https to support different proxy setups 2018-12-16 23:30:53 +01:00
azivner
b942163748 sync with electron net API (for system proxy support) - working, but WIP 2018-12-16 21:19:12 +01:00
azivner
5b6d15acb3 note path might not always include root explicitly 2018-12-16 10:41:47 +01:00
azivner
841420360e quick unhoist link/button 2018-12-15 20:29:08 +01:00
azivner
a680bb4612 unhoist note when activating note outside of the hoisted note subtree 2018-12-13 23:28:48 +01:00
azivner
f763e13996 fix searching without hoisting 2018-12-13 21:43:13 +01:00
azivner
e73e1262ae Merge branch 'stable' into hoist 2018-12-13 21:18:44 +01:00
azivner
b774d56cf7 note titles in jump to note start from hoisted note instead of root 2018-12-13 21:18:35 +01:00
azivner
bae55f2e8b release 0.25.2 2018-12-12 21:30:06 +01:00
azivner
6c16cdb011 recent notes and jump to note are filtered by hoisted note 2018-12-12 21:28:38 +01:00
azivner
86fcbb0354 keyboard shortcut for hoisting, hoisted note is always expanded and has arrow icon 2018-12-12 20:54:58 +01:00
azivner
17d030e800 continuing work on hoisting notes 2018-12-12 20:39:56 +01:00
azivner
6fbf28b30d hoisting notes WIP 2018-12-11 21:53:56 +01:00
azivner
8171b68b18 electron 4.0 beta 9, context menu padding 2018-12-11 19:50:31 +01:00
azivner
d30e3a4052 bind standard shortcuts on both command and ctrl modifiers, #254 2018-12-10 20:44:50 +01:00
azivner
87aab7ac5b fix attributes leaking into imported notes, #241 2018-12-10 20:29:49 +01:00
azivner
c46f5805b1 removed the note from readme about missing mac build 2018-12-09 21:50:29 +01:00
azivner
dd6a29dfc0 no ia32 release upload 2018-12-09 21:34:08 +01:00
azivner
a0933c7f10 release 0.25.1-beta 2018-12-09 21:22:33 +01:00
azivner
492adc2909 fix broken drag & drop, closes 252 2018-12-09 21:18:53 +01:00
azivner
90a52f57b5 recent notes route accepts slash in the param (problem with nginx etc.) 2018-12-09 14:30:19 +01:00
azivner
a1469854e8 Allow Trilium to work from non-root document paths, closes #253 2018-12-09 13:37:28 +01:00
azivner
e2c2993255 changes in build - linux-x64 also uses prebuilt binaries compatible with glibc 2.27 so e.g. ubuntu 18.04 works again. Also dropped build for linux-ia32 2018-12-09 11:41:32 +01:00
azivner
270d63b265 deactivated cut to note functionality in ckeditor build 2018-12-08 10:54:10 +01:00
azivner
1d004be91d ckeditor upgrade to 11.2.0 2018-12-08 09:48:36 +01:00
azivner
b8a74c727e copy paste, undo, redo, select all shortcuts supported on mac build 2018-12-02 14:04:53 +01:00
azivner
c87b592277 fix in the release script 2018-12-02 08:42:11 +01:00
azivner
cfa926602a release 0.25.0-beta 2018-12-02 00:30:07 +01:00
zadam
350cb52c07 Merge pull request #249 from nicoulaj/master
fix #248: crossorigin attribute is needed when including with type="module"
2018-12-02 00:27:59 +01:00
azivner
af195beb7e initial mac support + some other build changes 2018-12-02 00:26:45 +01:00
Julien Nicoulaud
cb00d42546 fix #248: crossorigin attribute is needed when including with type="module"
For more info, see:
 * https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
 * https://jakearchibald.com/2017/es-modules-in-browsers
2018-12-01 23:33:23 +01:00
azivner
ee0b0c3dfe minor export fixes 2018-11-30 22:43:03 +01:00
azivner
ddcb4a0e10 added another mime type for JS 2018-11-30 22:28:30 +01:00
azivner
8cbb29ee25 default location for data dir is now .local for linux and Roaming for windows 2018-11-30 19:56:20 +01:00
azivner
9da11ac144 electron 4 beta 8 2018-11-30 17:50:38 +01:00
azivner
ba7c8e77e5 add support for number precision in promoted attributes, closes #245 2018-11-30 17:36:41 +01:00
azivner
4577b03fc9 promoted attributes now use saved indicator (little check) instead of notification 2018-11-30 17:18:19 +01:00
azivner
72d83aa85e fix note cache - note entity after initialization doesn't contain ciphertext so decryption is not necessary 2018-11-30 15:51:55 +01:00
azivner
8ee80cb5f1 using dashes instead of underscores in header names to avoid the fact that nginx by default drops all headers with underscore in the header name 2018-11-30 15:49:35 +01:00
azivner
4cc08bff8b minor node updates in docker and server package 2018-11-30 13:56:36 +01:00
zadam
295cfb2d75 Merge pull request #247 from gabe565/master
Smaller Docker image
2018-11-30 13:38:47 +01:00
azivner
7775376b33 disable "cut to note" feature because of issues with CKEditor 2018-11-30 11:37:33 +01:00
azivner
9f64e994dc fix minor UI issue causing children overview not being decrypted right after entering protected session 2018-11-30 10:33:40 +01:00
azivner
ee1e4fc710 added "update pojo" stage in entity saving to avoid encrypting data on protected note directly on the entity 2018-11-30 10:20:03 +01:00
Gabe Cook
5ea62c710d Move devtron to devDependencies and update package-lock.json 2018-11-30 05:46:55 +00:00
Gabe Cook
aeca31d06a Add .git, bin, and docs to the .dockerignore 2018-11-30 05:46:49 +00:00
Gabe Cook
9cb9ea6ab5 Smaller Docker image by switching the base image to node:10.13.0-alpine and consolidating scripts 2018-11-30 05:41:53 +00:00
azivner
e37dd69827 link to Patterns of personal knowledge base 2018-11-28 22:05:23 +01:00
azivner
6c51696d1a also don't show "No results" for attr autocomplete 2018-11-27 19:43:34 +01:00
azivner
27787c8f37 attribute name and value autocompletes should not have autoselect since it's OK to enter value not in the autocomplete 2018-11-27 19:40:19 +01:00
azivner
e910595545 updated readme 2018-11-27 19:18:24 +01:00
azivner
a616739805 release 0.24.5 2018-11-27 15:34:15 +01:00
azivner
bea28de6a0 tab on autocomplete doesn't select first item, closes #243 2018-11-27 13:13:06 +01:00
azivner
4e198ca2f0 storing trilium version into export metadata 2018-11-27 10:31:55 +01:00
azivner
2fbd16a0e3 updated demo export according to latest format changes 2018-11-26 23:50:43 +01:00
azivner
76fc49f037 allow import of single HTML file too 2018-11-26 23:47:02 +01:00
azivner
139c99440f export stores note position and some other fixes 2018-11-26 23:39:43 +01:00
azivner
137b9dfa0b fix storing attributes and relinking noteIds 2018-11-26 23:19:19 +01:00
azivner
5f0fdd15eb fix adding sync entities during import 2018-11-26 22:37:59 +01:00
azivner
61e1427b83 fix matching of "b" in the note autcomplete highlighter 2018-11-26 22:35:19 +01:00
azivner
b3aa0ba47c entity events are not triggered on imported entities 2018-11-26 22:27:57 +01:00
azivner
56e2b44c25 fix import 2018-11-26 22:22:16 +01:00
azivner
4d5a17583f happy path tar import now works 2018-11-26 20:30:43 +01:00
azivner
71eda5aa3d import tar archive WIP 2018-11-26 14:47:46 +01:00
azivner
0711ea8dc8 filter out links and relations which are outside of the export 2018-11-25 22:38:09 +01:00
azivner
be206872d1 changed export model to single metadata file per exported .tar 2018-11-25 22:09:52 +01:00
azivner
fcf3fe8dcd tar export can now solve naming conflict 2018-11-25 15:17:28 +01:00
azivner
62dbd4062a on/off button for entering/leaving protected session has been changed to literal buttons 2018-11-25 14:12:33 +01:00
azivner
196e8b4380 extra icons 2018-11-25 14:05:54 +01:00
azivner
551e1255ff export WIP + some unrelated changes 2018-11-25 10:26:45 +01:00
azivner
e09b61d1ac single file export working, tar WIP 2018-11-24 20:58:38 +01:00
azivner
ee23bcc783 unified export dialog, WIP 2018-11-24 14:44:56 +01:00
azivner
3e351bd8d3 better positioning of nonmodal protected session dialog 2018-11-22 21:24:47 +01:00
azivner
0d3bc22d73 fix z-index of notification 2018-11-22 21:19:12 +01:00
azivner
d82898421e less obtrusive saved indicator, fixes #122 2018-11-22 20:25:49 +01:00
azivner
1db2f0c2c5 improved notifications, now with animations, in center and show up properly in the dialogs 2018-11-22 16:08:02 +01:00
azivner
6cd8a2203e create app icon only for electron build 2018-11-22 00:24:33 +01:00
azivner
08e062ab34 release 0.24.4-beta 2018-11-21 23:47:09 +01:00
azivner
3a06493459 partial workaround for the broken in page search (next & previous don't work, but at least highlighting works) 2018-11-21 23:39:19 +01:00
azivner
8159564885 fix .desktop + allow to turn this feature off 2018-11-21 11:19:33 +01:00
azivner
8ce3c1a480 generate local .desktop file so it shows among apps in linux desktop environments 2018-11-21 11:01:03 +01:00
azivner
dbc93f4a79 mitigations for tooltip flickering 2018-11-20 23:50:19 +01:00
azivner
92ffe321aa smaller context menu 2018-11-20 22:55:07 +01:00
azivner
6cb7d0098e changed layout a little bit to fix broken children overview in the electron/chrome 2018-11-20 22:49:10 +01:00
azivner
bdcb4361b2 simplification of note autocomplete result ordering by depth #240 2018-11-20 22:22:26 +01:00
azivner
15366d37d7 ordering results in autocomplete based on depth, closes #240 2018-11-20 21:22:20 +01:00
azivner
acd001501b release 0.24.3-beta 2018-11-20 13:01:41 +01:00
azivner
0019865807 disabling broken in page search 2018-11-20 12:54:03 +01:00
azivner
137ffcc4e3 enable line wrap for code editor 2018-11-20 10:49:03 +01:00
azivner
585398ad5c fix bug when saving non-text notes 2018-11-19 23:11:36 +01:00
azivner
50401954d1 disable cache for attribute name autocomplete 2018-11-19 22:17:08 +01:00
azivner
32a9df8489 fixes (and refactoring) for "empty attribute name" check 2018-11-19 22:06:51 +01:00
azivner
5bf5d1cac4 attribute dialog doesn't allow to (attempt to) save relation without target note 2018-11-19 21:58:52 +01:00
azivner
3608857f25 small fix to demo export 2018-11-19 21:09:59 +01:00
azivner
16a1dc12df jsdoc now doesn't include date into files to avoid unnecessary noise 2018-11-19 21:03:43 +01:00
azivner
9c834229b9 release 0.24.2-beta 2018-11-19 17:17:08 +01:00
azivner
3fd45b15e7 set icon and app name, closes #201 2018-11-19 17:16:22 +01:00
azivner
f20ab45576 fix absolute image paths to relative paths as part of parsing links 2018-11-19 15:00:49 +01:00
azivner
77a89d85c8 fix "copy image to clipboard" button 2018-11-19 12:12:58 +01:00
azivner
30249a353e renamed "mirror" relation to "inverse" relation 2018-11-19 12:07:33 +01:00
azivner
eb9bae9010 updated relation map in demo document 2018-11-19 11:47:40 +01:00
azivner
0c7ae527c5 allow dragging only one note at a time 2018-11-19 11:19:56 +01:00
azivner
fef4705e2f center button changed to "reset pan & zoom" 2018-11-19 11:14:55 +01:00
azivner
568c2c997f possibility to export single code note as markdown. UI fix of disabled buttons 2018-11-19 09:54:33 +01:00
azivner
d6b5cd6ead support saving files and images in markdown tar export 2018-11-19 09:46:24 +01:00
azivner
00ce379962 excludeFromExport support also in OPML 2018-11-19 09:34:05 +01:00
azivner
b1ed022771 release 0.24.1-beta 2018-11-19 00:06:44 +01:00
azivner
ad6cb6ba34 mirror relation has to target source note 2018-11-19 00:06:04 +01:00
azivner
2e76de5f34 minor relation map fixes 2018-11-18 23:57:39 +01:00
azivner
4f23f2515a fix relation saving 2018-11-18 23:36:21 +01:00
azivner
8e16cc2326 fix prompt mutability (autocomplete on answer input field) 2018-11-18 23:31:31 +01:00
azivner
49bca04ebb fix doubling of notes after some actions 2018-11-18 23:01:48 +01:00
azivner
05e9669eaf fixed relation map sizing issue 2018-11-18 22:49:53 +01:00
azivner
62a250a7fc fixes for tooltip handling 2018-11-18 20:57:52 +01:00
azivner
8299524682 fixed cleanup of deleted notes for protected notes 2018-11-18 11:34:40 +01:00
azivner
7691a59977 imported notes can reference root 2018-11-18 11:19:50 +01:00
azivner
3db2f6784d fix DB migration and consistency issues 2018-11-18 10:20:06 +01:00
azivner
48684d0509 fixed app termination after unsuccessful migration for electron 2018-11-18 09:05:50 +01:00
azivner
1ee8d9fd93 sql console executes selected text if there's a selection instead of the whole content 2018-11-18 08:29:56 +01:00
202 changed files with 32793 additions and 16214 deletions

View File

@@ -1,4 +1,7 @@
.git
.idea
/bin
/dist
/docs
/npm-debug.log
node_modules
npm-debug.log
dist
.idea

View File

@@ -1,21 +1,27 @@
FROM node:10.12.0
RUN apt-get update && apt-get install -y nasm
FROM node:10.15.0-alpine
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# Copy both package.json and package-lock.json
# where available (npm@5+)
COPY package*.json ./
COPY package.json package-lock.json ./
RUN npm install --production
# If you are building your code for production
# RUN npm install --only=production
# Install app dependencies
RUN set -x \
&& apk add --no-cache --virtual .build-dependencies \
autoconf \
automake \
g++ \
gcc \
libtool \
make \
nasm \
&& npm install --production \
&& apk del .build-dependencies
# Bundle app source
COPY . .
EXPOSE 8080
CMD [ "node", "src/www" ]
CMD [ "node", "./src/www" ]

View File

@@ -1,40 +1,37 @@
# Trilium Notes
[![Join the chat at https://gitter.im/trilium-notes/Lobby](https://badges.gitter.im/trilium-notes/Lobby.svg)](https://gitter.im/trilium-notes/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Trilium Notes is a hierarchical note taking application. Picture tells a thousand words:
Trilium Notes is a hierarchical note taking application with focus on building large personal knowledge bases. See [screenshots](https://github.com/zadam/trilium/wiki/Screenshot-tour) for quick overview:
![](https://raw.githubusercontent.com/wiki/zadam/trilium/images/screenshot.png)
See other pictures in [screenshot tour](https://github.com/zadam/trilium/wiki/Screenshot-tour).
## Features
* Notes can be arranged into arbitrarily deep hierarchy (tree)
* Notes can have more than 1 parents - see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes)
* Notes can be arranged into arbitrarily deep tree. Single note can be placed into multiple places in the tree (see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes))
* Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-editor#autoformat)
* Support for editing [notes with source code](https://github.com/zadam/trilium/wiki/Code-notes), including syntax highlighting
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation)
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation), full text search and [note hoisting](https://github.com/zadam/trilium/wiki/Note-hoisting)
* Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions)
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes)
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) with per-note granularity
* [Relation maps](https://github.com/zadam/trilium/wiki/Relation-map) for visualizing notes and their relations
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)
* Scales well in both usability and performance upwards of 100 000 notes
* Touch optimized [mobile frontend](https://github.com/zadam/trilium/wiki/Mobile-frontend) for smartphones and tablets
* [Night theme](https://github.com/zadam/trilium/wiki/Themes)
* [Evernote](https://github.com/zadam/trilium/wiki/Evernote-import) and [Markdown import & export](https://github.com/zadam/trilium/wiki/Markdown)
## Builds
Trilium is provided as either desktop application ([Electron](https://electronjs.org)-based) or web application hosted on your server.
Trilium is provided as either desktop application (Linux, Windows, Mac) or web application hosted on your server (Linux).
* If you want to use Trilium on the desktop, download binary release for your platform (currently Linux and Windows are supported) from [latest release](https://github.com/zadam/trilium/releases/latest), unzip the package and run ```trilium``` executable.
* If you want to use Trilium on the desktop, download binary release for your platform from [latest release](https://github.com/zadam/trilium/releases/latest), unzip the package and run ```trilium``` executable.
* If you want to install Trilium on server, follow [this page](https://github.com/zadam/trilium/wiki/Server-installation).
* Currently only recent Chrome and Firefox are supported (tested) browsers.
## Status
Trilium is beta quality software. While it is reasonably feature complete and is tested by its author, it lacks proper testing by more users. It's not yet recommended for daily use, but testing and experimentation is encouraged.
## Documentation
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
[See wiki for complete list of documentation pages.](https://github.com/zadam/trilium/wiki/)
You can also read [Patterns of personal knowledge base](https://github.com/zadam/trilium/wiki/Patterns-of-personal-knowledge-base) to get some inspiration on how you might use Trilium.

View File

@@ -1,8 +1,5 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=`jq -r ".version" package.json`
sudo docker build -t zadam/trilium:latest -t zadam/trilium:$1 .
sudo docker build -t zadam/trilium:latest -t zadam/trilium:$VERSION .

24
bin/build-linux-x64.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-linux-x64
rm -rf $BUILD_DIR
# we build x64 as second so that we keep X64 binaries in node_modules for local development and server build
echo "Rebuilding binaries for linux-x64"
./node_modules/.bin/electron-rebuild --arch=x64
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR
rm -r "$BUILD_DIR/resources/app/node_modules/sqlite3/lib/binding/*"
cp -r bin/deps/linux-x64/sqlite/electron* "$BUILD_DIR/resources/app/node_modules/sqlite3/lib/binding/"
rm -r $BUILD_DIR/resources/app/bin/deps
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
echo "Packaging linux x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

27
bin/build-mac-x64.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-mac-x64
rm -rf $BUILD_DIR
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=darwin --arch=x64 --overwrite --icon=src/public/images/app-icons/mac/icon.icns
# Mac build has by default useless directory level
mv "./dist/Trilium Notes-darwin-x64" $BUILD_DIR
echo "Copying required mac binaries"
MAC_RES_DIR=$BUILD_DIR/Trilium\ Notes.app/Contents/Resources/app
rm -r "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/*"
cp -r bin/deps/mac-x64/sqlite/* "$MAC_RES_DIR/node_modules/sqlite3/lib/binding/"
cp bin/deps/mac-x64/image/cjpeg "$MAC_RES_DIR/node_modules/mozjpeg/vendor/"
cp bin/deps/mac-x64/image/pngquant "$MAC_RES_DIR/node_modules/pngquant-bin/vendor/"
cp bin/deps/mac-x64/image/gifsicle "$MAC_RES_DIR/node_modules/giflossy/vendor/"
rm -r "$MAC_RES_DIR/bin/deps"
echo "Packaging mac x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

View File

@@ -1,13 +1,7 @@
#!/usr/bin/env bash
if [[ $# -eq 0 ]] ; then
echo "Missing argument of new version"
exit 1
fi
VERSION=$1
PKG_DIR=dist/trilium-linux-x64-server
NODE_VERSION=10.12.0
NODE_VERSION=10.15.0
rm -r $PKG_DIR
mkdir $PKG_DIR
@@ -30,9 +24,14 @@ cp -r ../../config-sample.ini ./
rm -r ./node_modules/electron*
rm -r ./node_modules/sqlite3/lib/binding/*
cp -r ../../bin/deps/linux-x64/sqlite/node* ./node_modules/sqlite3/lib/binding/
printf "#/bin/sh\n./node/bin/node src/www" > trilium.sh
chmod 755 trilium.sh
cd ..
VERSION=`jq -r ".version" ../package.json`
7z a trilium-linux-x64-server-${VERSION}.7z trilium-linux-x64-server

25
bin/build-win-x64.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env bash
BUILD_DIR=./dist/trilium-windows-x64
rm -rf $BUILD_DIR
./node_modules/.bin/electron-packager . --out=dist --executable-name=trilium --platform=win32 --arch=x64 --overwrite --icon=src/public/images/app-icons/win/icon.ico
mv "./dist/Trilium Notes-win32-x64" $BUILD_DIR
echo "Copying required windows binaries"
WIN_RES_DIR=$BUILD_DIR/resources/app
cp -r bin/deps/win-x64/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/win-x64/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/win-x64/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/win-x64/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
rm -r $WIN_RES_DIR/bin/deps
# removing software WebGL binaries because they are pretty huge and not necessary
rm -r $BUILD_DIR/swiftshader
echo "Packaging windows x64 electron distribution..."
VERSION=`jq -r ".version" package.json`
7z a $BUILD_DIR-${VERSION}.7z $BUILD_DIR

View File

@@ -8,30 +8,11 @@ echo "Deleting existing builds"
rm -r dist/*
echo "Rebuilding binaries for linux-ia32"
./node_modules/.bin/electron-rebuild --arch=ia32
bin/build-win-x64.sh
./node_modules/.bin/electron-packager . --out=dist --platform=linux --arch=ia32 --overwrite
bin/build-mac-x64.sh
./node_modules/.bin/electron-packager . --out=dist --platform=win32 --arch=x64 --overwrite
# building X64 linux as the last so electron-rebuild will prepare X64 binaries for local development
bin/build-linux-x64.sh
# we build x64 as second so that we keep X64 binaries in node_modules for local development and server build
echo "Rebuilding binaries for linux-x64"
./node_modules/.bin/electron-rebuild --arch=x64
./node_modules/.bin/electron-packager . --out=dist --platform=linux --arch=x64 --overwrite
echo "Copying required windows binaries"
WIN_RES_DIR=./dist/trilium-win32-x64/resources/app
cp -r bin/deps/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
echo "Cleaning up unnecessary binaries from all builds"
rm -r ./dist/trilium-linux-ia32/resources/app/bin/deps
rm -r ./dist/trilium-linux-x64/resources/app/bin/deps
rm -r ./dist/trilium-win32-x64/resources/app/bin/deps
bin/build-server.sh

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
bin/generate-cert.sh Normal file → Executable file
View File

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
VERSION=`jq -r ".version" package.json`
cd dist
echo "Packaging linux x64 electron distribution..."
7z a trilium-linux-x64-${VERSION}.7z trilium-linux-x64
echo "Packaging linux ia32 electron distribution..."
7z a trilium-linux-ia32-${VERSION}.7z trilium-linux-ia32
echo "Packaging windows x64 electron distribution..."
7z a trilium-windows-x64-${VERSION}.7z trilium-win32-x64

View File

@@ -42,18 +42,22 @@ git push origin $TAG
bin/build.sh
bin/package.sh
LINUX_X64_BUILD=trilium-linux-x64-$VERSION.7z
LINUX_IA32_BUILD=trilium-linux-ia32-$VERSION.7z
WINDOWS_X64_BUILD=trilium-windows-x64-$VERSION.7z
MAC_X64_BUILD=trilium-mac-x64-$VERSION.7z
SERVER_BUILD=trilium-linux-x64-server-$VERSION.7z
echo "Creating release in GitHub"
EXTRA=
if [[ $TAG == *"beta"* ]]; then
EXTRA=--pre-release
fi
github-release release \
--tag $TAG \
--name "$TAG release"
--name "$TAG release" $EXTRA
echo "Uploading linux x64 build"
@@ -62,13 +66,6 @@ github-release upload \
--name "$LINUX_X64_BUILD" \
--file "dist/$LINUX_X64_BUILD"
echo "Uploading linux ia32 build"
github-release upload \
--tag $TAG \
--name "$LINUX_IA32_BUILD" \
--file "dist/$LINUX_IA32_BUILD"
echo "Uploading windows x64 build"
github-release upload \
@@ -76,9 +73,14 @@ github-release upload \
--name "$WINDOWS_X64_BUILD" \
--file "dist/$WINDOWS_X64_BUILD"
echo "Packaging server version"
echo "Uploading mac x64 build"
bin/build-server.sh $VERSION
github-release upload \
--tag $TAG \
--name "$MAC_X64_BUILD" \
--file "dist/$MAC_X64_BUILD"
echo "Uploading linux x64 server build"
github-release upload \
--tag $TAG \

Binary file not shown.

View File

@@ -1,3 +1,9 @@
-- first fix deleted status of existing images
UPDATE note_images SET isDeleted = 1 WHERE noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1);
-- we don't need set data to null because table is going to be dropped anyway and we want image size into attribute
UPDATE images SET isDeleted = 1 WHERE imageId NOT IN (SELECT imageId FROM note_images WHERE isDeleted = 0);
-- allow null for note content (for deleted notes)
CREATE TABLE IF NOT EXISTS "notes_mig" (
`noteId` TEXT NOT NULL,

View File

@@ -0,0 +1 @@
UPDATE attributes SET isDeleted = 1 WHERE noteId IN (SELECT noteId FROM notes WHERE isDeleted = 1);

View File

@@ -0,0 +1 @@
UPDATE attributes SET isDeleted = 1 WHERE type = 'relation' AND value NOT IN (SELECT noteId FROM notes WHERE notes.isDeleted = 0);

View File

@@ -0,0 +1 @@
UPDATE attributes SET value = replace(value, 'mirrorRelation', 'inverseRelation') WHERE type = 'relation-definition';

View File

@@ -0,0 +1 @@
UPDATE attributes SET name = 'archived' where name = 'hideInAutocomplete';

View File

@@ -0,0 +1,2 @@
INSERT INTO options (name, value, dateCreated, dateModified, isSynced)
VALUES ('hoistedNoteId', 'root', '2018-12-11T18:31:00.874Z', '2018-12-11T18:31:00.874Z', 0);

View File

@@ -288,7 +288,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -730,7 +730,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -3010,7 +3010,7 @@ the backend.
<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#line234">line 234</a>
<a href="services_backend_script_api.js.html">services/backend_script_api.js</a>, <a href="services_backend_script_api.js.html#line236">line 236</a>
</li></ul></dd>
@@ -3814,7 +3814,7 @@ transactional by default.
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -511,7 +511,7 @@ Each note can have multiple (at least one) branches, meaning it can be placed in
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -216,7 +216,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -358,7 +358,7 @@ this is different concept than attribute/relation.</div>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

File diff suppressed because it is too large Load Diff

View File

@@ -403,7 +403,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -311,7 +311,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -288,7 +288,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -75,7 +75,7 @@ module.exports = ApiToken;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -133,6 +133,11 @@ class Attribute extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.isOwned;
}
}
module.exports = Attribute;</code></pre>
@@ -151,7 +156,7 @@ module.exports = Attribute;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -87,6 +87,11 @@ class Branch extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.origParentNoteId;
}
}
module.exports = Branch;</code></pre>
@@ -105,7 +110,7 @@ module.exports = Branch;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -93,7 +93,7 @@ module.exports = Entity;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -92,7 +92,7 @@ module.exports = Link;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -32,6 +32,7 @@ const Entity = require('./entity');
const Attribute = require('./attribute');
const protectedSessionService = require('../services/protected_session');
const repository = require('../services/repository');
const sql = require('../services/sql');
const dateUtils = require('../services/date_utils');
const LABEL = 'label';
@@ -102,7 +103,9 @@ class Note extends Entity {
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript() {
return (this.type === "code" || this.type === "file")
&amp;&amp; (this.mime.startsWith("application/javascript") || this.mime === "application/x-javascript");
&amp;&amp; (this.mime.startsWith("application/javascript")
|| this.mime === "application/x-javascript"
|| this.mime === "text/javascript");
}
/** @returns {boolean} true if this note is HTML */
@@ -394,6 +397,16 @@ class Note extends Entity {
*/
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
/**
* @param {string} name
* @returns {Promise&lt;Note>|null} target note of the relation or null (if target is empty or note was not found)
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
}
/**
* Based on enabled, label is either set or removed.
*
@@ -451,24 +464,32 @@ class Note extends Entity {
async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
/**
* @param {string} name
* @returns {Promise&lt;Note>|null} target note of the relation or null (if target is empty or note was not found)
* @return {Promise&lt;string[]>} return list of all descendant noteIds of this note. Returning just noteIds because number of notes can be huge. Includes also this note's noteId
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
async getDescendantNoteIds() {
return await sql.getColumn(`
WITH RECURSIVE
tree(noteId) AS (
SELECT ?
UNION
SELECT branches.noteId FROM branches
JOIN tree ON branches.parentNoteId = tree.noteId
JOIN notes ON notes.noteId = branches.noteId
WHERE notes.isDeleted = 0
AND branches.isDeleted = 0
)
SELECT noteId FROM tree`, [this.noteId]);
}
/**
* Finds child notes with given attribute name and value. Only own attributes are considered, not inherited ones
* Finds descendant notes with given attribute name and value. Only own attributes are considered, not inherited ones
*
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @param {string} [value] - attribute value
* @returns {Promise&lt;Note[]>}
*/
async findChildNotesWithAttribute(type, name, value) {
async getDescendantNotesWithAttribute(type, name, value) {
const params = [this.noteId, name];
let valueCondition = "";
@@ -500,22 +521,22 @@ class Note extends Entity {
}
/**
* Finds notes with given label name and value. Only own labels are considered, not inherited ones
* Finds descendant notes with given label name and value. Only own labels are considered, not inherited ones
*
* @param {string} name - label name
* @param {string} [value] - label value
* @returns {Promise&lt;Note[]>}
*/
async findChildNotesWithLabel(name, value) { return await this.findChildNotesWithAttribute(LABEL, name, value); }
async getDescendantNotesWithLabel(name, value) { return await this.getDescendantNotesWithAttribute(LABEL, name, value); }
/**
* Finds notes with given relation name and value. Only own relations are considered, not inherited ones
* Finds descendant notes with given relation name and value. Only own relations are considered, not inherited ones
*
* @param {string} name - relation name
* @param {string} [value] - relation value
* @returns {Promise&lt;Note[]>}
*/
async findChildNotesWithRelation(name, value) { return await this.findChildNotesWithAttribute(RELATION, name, value); }
async getDescendantNotesWithRelation(name, value) { return await this.getDescendantNotesWithAttribute(RELATION, name, value); }
/**
* Returns note revisions of this note.
@@ -615,10 +636,6 @@ class Note extends Entity {
// we do this here because encryption needs the note ID for the IV
this.generateIdIfNecessary();
if (this.isProtected) {
protectedSessionService.encryptNote(this);
}
if (!this.isDeleted) {
this.isDeleted = false;
}
@@ -633,6 +650,17 @@ class Note extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
if (pojo.isProtected) {
protectedSessionService.encryptNote(pojo);
}
delete pojo.jsonContent;
delete pojo.isContentAvailable;
delete pojo.__attributeCache;
}
}
module.exports = Note;</code></pre>
@@ -651,7 +679,7 @@ module.exports = Note;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -91,7 +91,7 @@ module.exports = NoteRevision;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -78,7 +78,7 @@ module.exports = Option;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -75,7 +75,7 @@ module.exports = RecentNote;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -594,7 +594,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -56,7 +56,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -253,6 +253,8 @@ function BackendScriptApi(startNote, currentNote, originEntity) {
*/
this.transactional = sql.transactional;
this.sql = sql;
/**
* Trigger tree refresh in all connected clients. This is required when some tree change happens in
* the backend.
@@ -278,7 +280,7 @@ module.exports = BackendScriptApi;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:27 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -719,7 +719,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

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#line16">line 16</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line17">line 17</a>
</li></ul></dd>
@@ -221,7 +221,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line22">line 22</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line23">line 23</a>
</li></ul></dd>
@@ -334,7 +334,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line24">line 24</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line25">line 25</a>
</li></ul></dd>
@@ -444,7 +444,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line20">line 20</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line21">line 21</a>
</li></ul></dd>
@@ -573,7 +573,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line41">line 41</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line42">line 42</a>
</li></ul></dd>
@@ -726,7 +726,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line33">line 33</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line34">line 34</a>
</li></ul></dd>
@@ -879,7 +879,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line60">line 60</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line61">line 61</a>
</li></ul></dd>
@@ -1057,7 +1057,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line197">line 197</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line198">line 198</a>
</li></ul></dd>
@@ -1188,7 +1188,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line157">line 157</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line158">line 158</a>
</li></ul></dd>
@@ -1292,7 +1292,7 @@
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line221">line 221</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line222">line 222</a>
</li></ul></dd>
@@ -1396,7 +1396,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#line203">line 203</a>
<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>
@@ -1500,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#line215">line 215</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line216">line 216</a>
</li></ul></dd>
@@ -1609,7 +1609,7 @@ if some action needs to happen on only one specific instance.
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line150">line 150</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line151">line 151</a>
</li></ul></dd>
@@ -1808,7 +1808,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line142">line 142</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line143">line 143</a>
</li></ul></dd>
@@ -1957,7 +1957,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line209">line 209</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line210">line 210</a>
</li></ul></dd>
@@ -2088,7 +2088,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line164">line 164</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line165">line 165</a>
</li></ul></dd>
@@ -2196,7 +2196,7 @@ otherwise (by e.g. createNoteLink())
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line188">line 188</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line189">line 189</a>
</li></ul></dd>
@@ -2373,7 +2373,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line110">line 110</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line111">line 111</a>
</li></ul></dd>
@@ -2526,7 +2526,138 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line227">line 227</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line228">line 228</a>
</li></ul></dd>
</dl>
<h4 class="name" id="setupElementTooltip"><span class="type-signature"></span>setupElementTooltip<span class="signature">($el)</span><span class="type-signature"></span></h4>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>$el</code></td>
<td class="type">
<span class="param-type">object</span>
</td>
<td class="description last">jquery object on which to setup the tooltip</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line234">line 234</a>
</li></ul></dd>
@@ -2661,7 +2792,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line180">line 180</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line181">line 181</a>
</li></ul></dd>
@@ -2796,7 +2927,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line172">line 172</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line173">line 173</a>
</li></ul></dd>
@@ -2846,7 +2977,7 @@ Internally this serializes the anonymous function into string and sends it to ba
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -279,7 +279,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: entities/attribute.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: entities/attribute.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>class Attribute {
constructor(treeCache, row) {
this.treeCache = treeCache;
/** @param {string} attributeId */
this.attributeId = row.attributeId;
/** @param {string} noteId */
this.noteId = row.noteId;
/** @param {string} type */
this.type = row.type;
/** @param {string} name */
this.name = row.name;
/** @param {string} value */
this.value = row.value;
/** @param {int} position */
this.position = row.position;
/** @param {boolean} isInheritable */
this.isInheritable = row.isInheritable;
/** @param {boolean} isDeleted */
this.isDeleted = row.isDeleted;
/** @param {string} dateCreated */
this.dateCreated = row.dateCreated;
/** @param {string} dateModified */
this.dateModified = row.dateModified;
}
/** @returns {NoteShort} */
async getNote() {
return await this.treeCache.getNote(this.noteId);
}
get toString() {
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
}
}</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Branch.html">Branch</a></li><li><a href="FrontendScriptApi.html">FrontendScriptApi</a></li><li><a href="NoteFull.html">NoteFull</a></li><li><a href="NoteShort.html">NoteShort</a></li></ul><h3><a href="global.html">Global</a></h3>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@@ -42,7 +42,7 @@ class Branch {
/** @param {string} */
this.prefix = row.prefix;
/** @param {boolean} */
this.isExpanded = row.isExpanded;
this.isExpanded = !!row.isExpanded;
}
/** @returns {NoteShort} */
@@ -76,7 +76,7 @@ export default Branch;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -64,7 +64,7 @@ export default NoteFull;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -26,7 +26,14 @@
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
<pre class="prettyprint source linenums"><code>import server from '../services/server.js';
const LABEL = 'label';
const LABEL_DEFINITION = 'label-definition';
const RELATION = 'relation';
const RELATION_DEFINITION = 'relation-definition';
/**
* This note's representation is used in note tree and is kept in TreeCache.
* Its notable omission is the note content.
*/
@@ -99,6 +106,140 @@ class NoteShort {
return await this.treeCache.getNotes(this.getChildNoteIds());
}
/**
* @param {string} [name] - attribute name to filter
* @returns {Promise&lt;Attribute[]>}
*/
async getAttributes(name) {
if (!this.attributeCache) {
this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
}
if (name) {
return this.attributeCache.filter(attr => attr.name === name);
}
else {
return this.attributeCache;
}
}
/**
* @param {string} [name] - label name to filter
* @returns {Promise&lt;Attribute[]>} all note's labels (attributes with type label), including inherited ones
*/
async getLabels(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
}
/**
* @param {string} [name] - label name to filter
* @returns {Promise&lt;Attribute[]>} all note's label definitions, including inherited ones
*/
async getLabelDefinitions(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
}
/**
* @param {string} [name] - relation name to filter
* @returns {Promise&lt;Attribute[]>} all note's relations (attributes with type relation), including inherited ones
*/
async getRelations(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
}
/**
* @param {string} [name] - relation name to filter
* @returns {Promise&lt;Attribute[]>} all note's relation definitions including inherited ones
*/
async getRelationDefinitions(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise&lt;boolean>} true if note has an attribute with given type and name (including inherited)
*/
async hasAttribute(type, name) {
return !!await this.getAttribute(type, name);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise&lt;Attribute>} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
*/
async getAttribute(type, name) {
const attributes = await this.getAttributes();
return attributes.find(attr => attr.type === type &amp;&amp; attr.name === name);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise&lt;string>} attribute value of given type and name or null if no such attribute exists.
*/
async getAttributeValue(type, name) {
const attr = await this.getAttribute(type, name);
return attr ? attr.value : null;
}
/**
* @param {string} name - label name
* @returns {Promise&lt;boolean>} true if label exists (including inherited)
*/
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise&lt;boolean>} true if relation exists (including inherited)
*/
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
/**
* @param {string} name - label name
* @returns {Promise&lt;Attribute>} label if it exists, null otherwise
*/
async getLabel(name) { return await this.getAttribute(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise&lt;Attribute>} relation if it exists, null otherwise
*/
async getRelation(name) { return await this.getAttribute(RELATION, name); }
/**
* @param {string} name - label name
* @returns {Promise&lt;string>} label value if label exists, null otherwise
*/
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise&lt;string>} relation value if relation exists, null otherwise
*/
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
/**
* @param {string} name
* @returns {Promise&lt;Note>|null} target note of the relation or null (if target is empty or note was not found)
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
}
/**
* Clear note's attributes cache to force fresh reload for next attribute request.
* Cache is note instance scoped.
*/
invalidateAttributeCache() {
this.attributeCache = null;
}
get toString() {
return `Note(noteId=${this.noteId}, title=${this.title})`;
}
@@ -107,6 +248,7 @@ class NoteShort {
const dto = Object.assign({}, this);
delete dto.treeCache;
delete dto.archived;
delete dto.attributeCache;
return dto;
}
@@ -128,7 +270,7 @@ export default NoteShort;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

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#line47">line 47</a>
<a href="services_frontend_script_api.js.html">services/frontend_script_api.js</a>, <a href="services_frontend_script_api.js.html#line48">line 48</a>
</li></ul></dd>
@@ -339,7 +339,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -56,7 +56,7 @@
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -34,6 +34,7 @@ import linkService from './link.js';
import treeCache from './tree_cache.js';
import noteDetailService from './note_detail.js';
import noteTypeService from './note_type.js';
import noteTooltipService from './note_tooltip.js';
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@@ -253,6 +254,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
* @param {array} types - list of mime types to be used
*/
this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
/**
* @method
* @param {object} $el - jquery object on which to setup the tooltip
*/
this.setupElementTooltip = noteTooltipService.setupElementTooltip
}
export default FrontendScriptApi;</code></pre>
@@ -271,7 +278,7 @@ export default FrontendScriptApi;</code></pre>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Nov 15 2018 13:33:28 GMT+0100 (Central European Standard Time)
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a>
</footer>
<script> prettyPrint(); </script>

View File

@@ -6,6 +6,7 @@ const log = require('./src/services/log');
const cls = require('./src/services/cls');
const url = require("url");
const port = require('./src/services/port');
const appIconService = require('./src/services/app_icon');
const app = electron.app;
const globalShortcut = electron.globalShortcut;
@@ -13,6 +14,8 @@ const globalShortcut = electron.globalShortcut;
// Adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();
appIconService.installLocalAppIcon();
// Prevent window being garbage collected
let mainWindow;
@@ -70,6 +73,8 @@ app.on('activate', () => {
});
app.on('ready', async () => {
app.setAppUserModelId('com.github.zadam.trilium');
mainWindow = await createMainWindow();
const result = globalShortcut.register('CommandOrControl+Alt+P', cls.wrap(async () => {

7
jsdoc-conf.json Normal file
View File

@@ -0,0 +1,7 @@
{
"templates": {
"default": {
"includeDate": false
}
}
}

512
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.23.1",
"version": "0.27.2-beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -65,21 +65,21 @@
}
},
"@jimp/bmp": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.5.4.tgz",
"integrity": "sha512-P/ezH1FuoM3FwS0Dm2ZGkph4x5/rPBzFLEZor7KQkmGUnYEIEG4o0BUcAWFmJOp2HgzbT6O2SfrpJNBOcVACzQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.6.0.tgz",
"integrity": "sha512-zZOcVT1zK/1QL5a7qirkzPPgDKB1ianER7pBdpR2J71vx/g8MnrPbL3h/jEVPxjdci2Hph/VWhc/oLBtTbqO8w==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"bmp-js": "^0.1.0",
"core-js": "^2.5.7"
}
},
"@jimp/core": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.5.4.tgz",
"integrity": "sha512-n3uvHy2ndUKItmbhnRO8xmU8J6KR+v6CQxO9sbeUDpSc3VXc1PkqrA8ZsCVFCjnDFcGBXL+MJeCTyQzq5W9Crw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.6.0.tgz",
"integrity": "sha512-ngAkyCLtX7buc2QyFy0ql/j4R2wGYQVsVhW2G3Y0GVAAklRIFIUYpyNKrqs228xA8f2O6XStbDStFlYkt7uNeg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"any-base": "^1.1.0",
"buffer": "^5.2.0",
"core-js": "^2.5.7",
@@ -114,252 +114,252 @@
}
},
"@jimp/custom": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.5.4.tgz",
"integrity": "sha512-tLfyJoyouDl2J3RPFGfDzTtE+4S8ljqJUmLzy/cmx1n7+xS5TpLPdPskp7UaeAfNTqdF4CNAm94KYoxTZdj2mg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.6.0.tgz",
"integrity": "sha512-+YZIWhf03Rfbi+VPbHomKInu3tcntF/aij/JrIJd1QZq13f8m3mRNxakXupiL18KH0C8BPNDk8RiwFX+HaOw3A==",
"requires": {
"@jimp/core": "^0.5.4",
"@jimp/core": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/gif": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.5.0.tgz",
"integrity": "sha512-HVB4c7b8r/yCpjhCjVNPRFLuujTav5UPmcQcFJjU6aIxmne6e29rAjRJEv3UMamHDGSu/96PzOsPZBO5U+ZGww==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.6.0.tgz",
"integrity": "sha512-aWQ02P0ymTN1eh0BVsY+84wMdb/QeiVpCNQZl9y50cRnpuMM8TTmF/ZdCEBDiTRFcwXzHsqBXcLwEcYp3X2lTw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"omggif": "^1.0.9"
}
},
"@jimp/jpeg": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.5.4.tgz",
"integrity": "sha512-YaPWm+YSGCThNE/jLMckM3Qs6uaMxd/VsHOnEaqu5tGA4GFbfVaWHjKqkNGAFuiNV+HdgKlNcCOF3of+elvzqQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.6.0.tgz",
"integrity": "sha512-quYb+lM4h57jQvr2q9dEIkc0laTljws4dunIdFhJRfa5UlNL5mHInk8h5MxyALo0mZdT07TAcxiDHw5QXZ28JQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"jpeg-js": "^0.3.4"
}
},
"@jimp/plugin-blit": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.5.4.tgz",
"integrity": "sha512-WqDYOugv76hF1wnKy7+xPGf9PUbcm9vPW28/jHWn1hjbb2GnusJ2fVEFad76J/1SPfhrQ2Uebf2QCWJuLmOqZg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.6.0.tgz",
"integrity": "sha512-LjiCa+8OT2fgmvBpZt0ogurg/eu5kB8ZFWDRwHPcf8i+058sZC20dar/qrjVd5Knssq4ynjb5oAHsGuJq16Rqw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-blur": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.5.0.tgz",
"integrity": "sha512-5k0PXCA1RTJdITL7yMAyZ5tGQjKLHqFvwdXj/PCoBo5PuMyr0x6qfxmQEySixGk/ZHdDxMi80vYxHdKHjNNgjg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.6.0.tgz",
"integrity": "sha512-/vjGcEiHda6OLTCYqXPFkfSTbL+RatZoGcp1vewcWqChUccn9QVINTlxB7nEI/3Nb/i7KdhOPNEQh1k6q6QXsw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-color": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.5.5.tgz",
"integrity": "sha512-hWeOqNCmLguGYLhSvBrpfCvlijsMEVaLZAOod62s1rzWnujozyKOzm2eZe+W3To6mHbp5RGJNVrIwHBWMab4ug==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.6.0.tgz",
"integrity": "sha512-mvDeAwN8ZpDkOaABMJ0w9zUzo9OOtu1qvvPkSirXDTMiXt1nsbfz8BoeoD7nU2MFhQj5MiGjH65UDnsH5ZzYuw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"tinycolor2": "^1.4.1"
}
},
"@jimp/plugin-contain": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.5.4.tgz",
"integrity": "sha512-8YJh4FI3S69unri0nJsWeqVLeVGA77N2R0Ws16iSuCCD/5UnWd9FeWRrSbKuidBG6TdMBaG2KUqSYZeHeH9GOQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.6.0.tgz",
"integrity": "sha512-gPHnoQkDztMbvnTVo01BaMoM/hhDJdeJ7FRToD4p4Qvdor4V0I6NXtjOeUPXfD94miTgh/UTyJDqeG4GZzi4sA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-cover": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.5.4.tgz",
"integrity": "sha512-2Rur7b44WiDDgizUI2M2uYWc1RmfhU5KjKS1xXruobjQ0tXkf5xlrPXSushq0hB6Ne0Ss6wv0+/6eQ8WeGHU2w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.6.0.tgz",
"integrity": "sha512-iv9lA2v3qv+x3eaTThtyzFg+hO8/pSnM8NBymC5OlpSJnR54aWi7BVFXLJAF27T4EZyXko432PVul2IdY3BEPw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-crop": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.5.4.tgz",
"integrity": "sha512-6t0rqn4VazquGk48tO6hFBrQ+nkvC+A1RnR6UM/m8ZtG2/yjpwF0MXcpgJI1Fb+a4Ug7BY1fu2GPcZOhnAVK/g==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.6.0.tgz",
"integrity": "sha512-YftdmFZ2YnZDYyBulkStCt2MZbKKfbjytkE+6i3Djk2b/Rfryg5xjgzVnAumCRQJhVPukexrnc2V7KKbEgx7mQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-displace": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.5.0.tgz",
"integrity": "sha512-Bec7SQvnmKia4hOXEDjeNVx7vo/1bWqjuV6NO8xbNQcAO3gaCl91c9FjMDhsfAVb0Ou6imhbIuFPrLxorXsecQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.6.0.tgz",
"integrity": "sha512-kkva5Fy3r7J7QmiqYQ5c9NeUKKkN7+KSfCGsZ6tkRHK4REMIXhQO/OnJN8XG6RReV29O6QykdyeTXDiHUDiROw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-dither": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.5.0.tgz",
"integrity": "sha512-We2WJQsD/Lm8oqBFp/vUv9/5r2avyenL+wNNu/s2b1HqA5O4sPGrjHy9K6vIov0NroQGCQ3bNznLkTmjiHKBcg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.6.0.tgz",
"integrity": "sha512-ILSG7bl3SOqmcIa9C4nBvs0h0E0ObnMbeKWUZiNuz6i0OAlbxryiIfU4j0UVQD5XqT9ksC5mviVNrvOMw4SZLw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-flip": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.5.0.tgz",
"integrity": "sha512-D/ehBQxLMNR7oNd80KXo4tnSET5zEm5mR70khYOTtTlfti/DlLp3qOdjPOzfLyAdqO7Ly4qCaXrIsnia+pfPrA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.6.0.tgz",
"integrity": "sha512-MXGGwABjERvfqVadEzJuVAmbsEQfjxXD0O/mMBegU1Qh7/JmnKAVplQCnojsMPxUdao/FKZjQqOnB/j4LLJtOQ==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-gaussian": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.5.0.tgz",
"integrity": "sha512-Ln4kgxblv0/YzLBDb/J8DYPLhDzKH87Y8yHh5UKv3H+LPKnLaEG3L4iKTE9ivvdocnjmrtTFMYcWv2ERSPeHcg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.6.0.tgz",
"integrity": "sha512-RUsBCyj6Ukxgn/TU8v6c6WRbSFqKM0iknLVqDkKIuiOyJB7ougv66fqomh/i/h3ihIkEnf50BuO0c3ovrczfvw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-invert": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.5.0.tgz",
"integrity": "sha512-/vyKeIi3T7puf+8ruWovTjzDC585EnTwJ+lGOOUYiNPsdn4JDFe1B3xd+Ayv9aCQbXDIlPElZaM9vd/+wqDiIQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.6.0.tgz",
"integrity": "sha512-zTCqK8el6eqcNKAxw0y57gHBFgxygI5iM8dQDPyqsvVWO71i8XII7ubnJhEvPPN7vhIKlOSnS9XXglezvJoX4Q==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-mask": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.5.4.tgz",
"integrity": "sha512-mUJ04pCrUWaJGXPjgoVbzhIQB8cVobj2ZEFlGO3BEAjyylYMrdJlNlsER8dd7UuJ2L/a4ocWtFDdsnuicnBghQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.6.0.tgz",
"integrity": "sha512-zkZVqAA7lxWhkn5EbPjBQ6tPluYIGfLMSX4kD1gksj+MVJJnVAd459AVuEXCvkUvv4wG5AlH8m6ve5NZj9vvxw==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-normalize": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.5.4.tgz",
"integrity": "sha512-Q5W0oEz9wxsjuhvHAJynI/OqXZcmqEAuRONQId7Aw5ulCXSOg9C4y2a67EO7aZAt55T+zMVxI9UpVUpzVvO6hw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.6.0.tgz",
"integrity": "sha512-7bNGT+S0rw9gvmxpkNsA19JSqBZYFrAn9QhEmoN4HIimdKtJaoLJh/GnxrPuOBLuv1IPJntoTOOWvOmfrQ6/ww==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-print": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.5.4.tgz",
"integrity": "sha512-DOZr5TY9WyMWFBD37oz7KpTEBVioFIHQF/gH5b3O5jjFyj4JPMkw7k3kVBve9lIrzIYrvLqe0wH59vyAwpeEFg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.6.0.tgz",
"integrity": "sha512-kXNHYo7bGQiMZkUqhCvm6OomjJtZnLGs7cgXp9qsCfPcDBLLW+X3oxnoLaePQMlpQt6hX/lzFnNaWKv/KB1jlA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"load-bmfont": "^1.4.0"
}
},
"@jimp/plugin-resize": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.5.4.tgz",
"integrity": "sha512-lXNprNAT0QY1D1vG/1x6urUTlWuZe2dfL29P81ApW2Yfcio471+oqo45moX5FLS0q24xU600g7cHGf2/TzqSfA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.6.0.tgz",
"integrity": "sha512-m0AA/mPkJG++RuftBFDUMRenqgIN/uSh88Kqs33VURYaabApni4ML3QslE1TCJtl2Lnu1eosxYlbzODjHx49eg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-rotate": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.5.4.tgz",
"integrity": "sha512-SIdUpMc8clObMchy8TnjgHgcXEQM992z5KavgiuOnCuBlsmSHtE3MrXTOyMW0Dn3gqapV9Y5vygrLm/BVtCCsg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.6.0.tgz",
"integrity": "sha512-1QGlIisyxs2HNLuynq/ETc4h7E6At3yR+IYAhG9U4KONG4RqlIy0giyDhnfEZaiqOE+O7f+0Z7zN6GoSHmQjzg==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugin-scale": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.5.0.tgz",
"integrity": "sha512-5InIOr3cNtrS5aQ/uaosNf28qLLc0InpNGKFmGFTv8oqZqLch6PtDTjDBZ1GGWsPdA/ljy4Qyy7mJO1QBmgQeQ==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.6.0.tgz",
"integrity": "sha512-le/ttYwYioNPRoMlMaoJMCTv+m8d1v0peo/3J8E6Rf9ok7Bw3agkvjL9ILnsmr8jXj1YLrBSPKRs5nJ6ziM/qA==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7"
}
},
"@jimp/plugins": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.5.5.tgz",
"integrity": "sha512-9oF6LbSM/K7YkFCcxaPaD8NUkL/ZY8vT8NIGfQ/NpX+tKQtcsLHcRavHpUC+M1xXShv/QGx9OdBV/jgiu82QYg==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.6.0.tgz",
"integrity": "sha512-9+znfBJM1B31kvw+IcQFnAuDntQhwca/SONFnKOSZ8BNiQdiuTNbXHFxOo3tvdv1ngtB+LkkiTgK+QoF358b8g==",
"requires": {
"@jimp/plugin-blit": "^0.5.4",
"@jimp/plugin-blur": "^0.5.0",
"@jimp/plugin-color": "^0.5.5",
"@jimp/plugin-contain": "^0.5.4",
"@jimp/plugin-cover": "^0.5.4",
"@jimp/plugin-crop": "^0.5.4",
"@jimp/plugin-displace": "^0.5.0",
"@jimp/plugin-dither": "^0.5.0",
"@jimp/plugin-flip": "^0.5.0",
"@jimp/plugin-gaussian": "^0.5.0",
"@jimp/plugin-invert": "^0.5.0",
"@jimp/plugin-mask": "^0.5.4",
"@jimp/plugin-normalize": "^0.5.4",
"@jimp/plugin-print": "^0.5.4",
"@jimp/plugin-resize": "^0.5.4",
"@jimp/plugin-rotate": "^0.5.4",
"@jimp/plugin-scale": "^0.5.0",
"@jimp/plugin-blit": "^0.6.0",
"@jimp/plugin-blur": "^0.6.0",
"@jimp/plugin-color": "^0.6.0",
"@jimp/plugin-contain": "^0.6.0",
"@jimp/plugin-cover": "^0.6.0",
"@jimp/plugin-crop": "^0.6.0",
"@jimp/plugin-displace": "^0.6.0",
"@jimp/plugin-dither": "^0.6.0",
"@jimp/plugin-flip": "^0.6.0",
"@jimp/plugin-gaussian": "^0.6.0",
"@jimp/plugin-invert": "^0.6.0",
"@jimp/plugin-mask": "^0.6.0",
"@jimp/plugin-normalize": "^0.6.0",
"@jimp/plugin-print": "^0.6.0",
"@jimp/plugin-resize": "^0.6.0",
"@jimp/plugin-rotate": "^0.6.0",
"@jimp/plugin-scale": "^0.6.0",
"core-js": "^2.5.7",
"timm": "^1.6.1"
}
},
"@jimp/png": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.5.4.tgz",
"integrity": "sha512-J2NU7368zihF1HUZdmpXsL/Hhyf+I3ubmK+6Uz3Uoyvtk1VS7dO3L0io6fJQutfWmPZ4bvu6Ry022oHjbi6QCA==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.6.0.tgz",
"integrity": "sha512-DBtMyQyrJxuKI7/1dVqLek+rCMM8U6BSOTHgo05wU7lhJKTB6fn2tbYfsnHQKzd9ld1M2qKuC+O1GTVdB2yl6w==",
"requires": {
"@jimp/utils": "^0.5.0",
"@jimp/utils": "^0.6.0",
"core-js": "^2.5.7",
"pngjs": "^3.3.3"
}
},
"@jimp/tiff": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.5.4.tgz",
"integrity": "sha512-hr7Zq3eWjAZ+itSwuAObIWMRNv7oHVM3xuEDC2ouP7HfE7woBtyhCyfA7u12KlgtM57gKWeogXqTlewRGVzx6g==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.6.0.tgz",
"integrity": "sha512-PV95CquEsolFziq0zZrAEJIzZSKwMK89TvkOXTPDi/xesgdXGC2rtG1IZFpC9L4UX5hi/M5GaeJa49xULX6Nqw==",
"requires": {
"core-js": "^2.5.7",
"utif": "^2.0.1"
}
},
"@jimp/types": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.5.4.tgz",
"integrity": "sha512-nbZXM6TsdpnYHIBd8ZuoxGpvmxc2SqiggY30/bhOP/VJQoDBzm2v/20Ywz5M0snpIK2SdYG52eZPNjfjqUP39w==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.6.0.tgz",
"integrity": "sha512-j4tm82huEWpLrwave/2NYnMTY6us/6K9Js6Vd/CHoM/ki8M71tMXEVzc8tly92wtnEzQ9+FEk0Ue6pYo68m/5A==",
"requires": {
"@jimp/bmp": "^0.5.4",
"@jimp/gif": "^0.5.0",
"@jimp/jpeg": "^0.5.4",
"@jimp/png": "^0.5.4",
"@jimp/tiff": "^0.5.4",
"@jimp/bmp": "^0.6.0",
"@jimp/gif": "^0.6.0",
"@jimp/jpeg": "^0.6.0",
"@jimp/png": "^0.6.0",
"@jimp/tiff": "^0.6.0",
"core-js": "^2.5.7",
"timm": "^1.6.1"
}
},
"@jimp/utils": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.5.0.tgz",
"integrity": "sha512-7H9RFVU+Li2XmEko0GGyzy7m7JjSc7qa+m8l3fUzYg2GtwASApjKF/LSG2AUQCUmDKFLdfIEVjxvKvZUJFEmpw==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.6.0.tgz",
"integrity": "sha512-z5iYEfqc45vlYweROneNkjv32en6jS7lPL/eMLIvaEcQAHaoza20Dw8fUoJ0Ht9S92kR74xeTunAZq+gK2w67Q==",
"requires": {
"core-js": "^2.5.7"
}
@@ -399,9 +399,9 @@
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow=="
},
"@types/node": {
"version": "8.10.37",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.37.tgz",
"integrity": "sha512-Jp39foY8Euv/PG4OGPyzxis82mnjcUtXLEMA8oFMCE4ilmuJgZPdV2nZNV1moz+99EJTtcpOSgDCgATUwABKig==",
"version": "10.12.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
"dev": true
},
"abab": {
@@ -426,7 +426,8 @@
"accessibility-developer-tools": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz",
"integrity": "sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ="
"integrity": "sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=",
"dev": true
},
"acorn": {
"version": "5.7.3",
@@ -670,9 +671,9 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
},
"asar": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/asar/-/asar-0.14.5.tgz",
"integrity": "sha512-2Di/TnY1sridHFKMFgxBh0Wk0gVxSZN4qQhRhjJn3UywZAvP5MHI0RNVSkpzmJ+n6t0BC8w/+1257wtSgQ3Kdg==",
"version": "0.14.6",
"resolved": "https://registry.npmjs.org/asar/-/asar-0.14.6.tgz",
"integrity": "sha512-ZqybKcdO5At6y3ge2RHxVImc6Eltb2t3sxT7lk4T4zjZBSFUuIGCIZY6f41dCjlvJSizN5QPRr8YTgMhpgBjLg==",
"dev": true,
"requires": {
"chromium-pickle-js": "^0.2.0",
@@ -681,7 +682,7 @@
"glob": "^6.0.4",
"minimatch": "^3.0.3",
"mkdirp": "^0.5.0",
"mksnapshot": "^0.3.0",
"mksnapshot": "^0.3.4",
"tmp": "0.0.28"
},
"dependencies": {
@@ -968,7 +969,8 @@
"bluebird": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz",
"integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg=="
"integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==",
"dev": true
},
"bmp-js": {
"version": "0.1.0",
@@ -1818,9 +1820,9 @@
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
},
"debug": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
},
@@ -2033,7 +2035,7 @@
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
}
@@ -2202,6 +2204,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/devtron/-/devtron-1.4.0.tgz",
"integrity": "sha1-tedIvW6Vu+cL/MaKrm/mlhGUQeE=",
"dev": true,
"requires": {
"accessibility-developer-tools": "^2.11.0",
"highlight.js": "^9.3.0",
@@ -2372,12 +2375,12 @@
"integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ=="
},
"electron": {
"version": "4.0.0-beta.7",
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.0-beta.7.tgz",
"integrity": "sha512-770Hzxq10nQrzq39uVmvHLNKpPY3TCNrk+IYGDQTNWqmkreXZX6+9iflMMo+xdg1ZHysrTj1QQZvsjjBY176pg==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/electron/-/electron-4.0.1.tgz",
"integrity": "sha512-kBWDLn1Vq8Tm6+/HpQc8gkjX7wJyQI8v/lf2kAirfi0Q4cXh6vBjozFvV1U/9gGCbyKnIDM+m8/wpyJIjg4w7g==",
"dev": true,
"requires": {
"@types/node": "^8.0.24",
"@types/node": "^10.12.18",
"electron-download": "^4.1.0",
"extract-zip": "^1.0.3"
}
@@ -2524,10 +2527,20 @@
}
}
},
"electron-notarize": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-0.0.5.tgz",
"integrity": "sha512-YzrqZ6RDQ7Wt2RWlxzRoQUuxnTeXrfp7laH7XKcmQqrZ6GaAr50DMPvFMpqDKdrZSHSbcgZgB7ktIQbjvITmCQ==",
"dev": true,
"requires": {
"debug": "^4.1.0",
"fs-extra": "^7.0.0"
}
},
"electron-osx-sign": {
"version": "0.4.10",
"resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.10.tgz",
"integrity": "sha1-vk87ibKnWh3F8eckkIGrKSnKOiY=",
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.11.tgz",
"integrity": "sha512-VVd40nrnVqymvFrY9ZkOYgHJOvexHHYTR3di/SN+mjJ0OWhR1I8BRVj3U+Yamw6hnkZZNKZp52rqL5EFAAPFkQ==",
"dev": true,
"requires": {
"bluebird": "^3.5.0",
@@ -2535,7 +2548,7 @@
"debug": "^2.6.8",
"isbinaryfile": "^3.0.2",
"minimist": "^1.2.0",
"plist": "^2.1.0"
"plist": "^3.0.1"
},
"dependencies": {
"debug": {
@@ -2550,69 +2563,50 @@
}
},
"electron-packager": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-12.2.0.tgz",
"integrity": "sha512-T5W/FIK4VXhYIOWxkehmz6zXt2S/sA9JZ3AL+/jeKCicQY6QVQ0K8B7W801L+GPTwbgTPycHjO+iqEf1BhZ+Iw==",
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-13.0.1.tgz",
"integrity": "sha512-fXfldaZ1wihpPaMTSGMxvCeETJwVArlnMmKafVXLJbbZwS+WTjY4iL7ju9WMQ0LNGuiiIwSMCQFxt5iA087mqg==",
"dev": true,
"requires": {
"asar": "^0.14.0",
"debug": "^3.0.0",
"debug": "^4.0.1",
"electron-download": "^4.1.1",
"electron-osx-sign": "^0.4.1",
"electron-notarize": "^0.0.5",
"electron-osx-sign": "^0.4.11",
"extract-zip": "^1.0.3",
"fs-extra": "^5.0.0",
"fs-extra": "^7.0.0",
"galactus": "^0.2.1",
"get-package-info": "^1.0.0",
"nodeify": "^1.0.1",
"parse-author": "^2.0.0",
"pify": "^3.0.0",
"plist": "^2.0.0",
"pify": "^4.0.0",
"plist": "^3.0.0",
"rcedit": "^1.0.0",
"resolve": "^1.1.6",
"sanitize-filename": "^1.6.0",
"semver": "^5.3.0",
"yargs-parser": "^10.0.0"
"yargs-parser": "^11.0.0"
},
"dependencies": {
"camelcase": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz",
"integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==",
"dev": true
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
},
"fs-extra": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"pify": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
"dev": true
},
"yargs-parser": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz",
"integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==",
"version": "11.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
"integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
"dev": true,
"requires": {
"camelcase": "^4.1.0"
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
@@ -4303,7 +4297,7 @@
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
@@ -4337,9 +4331,9 @@
}
},
"get-port": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/get-port/-/get-port-4.0.0.tgz",
"integrity": "sha512-Yy3yNI2oShgbaWg4cmPhWjkZfktEvpKI09aDX4PZzNtlU9obuYrX7x2mumQsrNxlF+Ls7OtMQW/u+X4s896bOQ=="
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-port/-/get-port-4.1.0.tgz",
"integrity": "sha512-4/fqAYrzrzOiqDrdeZRKXGdTGgbkfTEumGlNQPeP6Jy8w0PzN9mzeNQ3XgHaTNie8pQ3hOUkrwlZt2Fzk5H9mA=="
},
"get-proxy": {
"version": "1.1.0",
@@ -4903,7 +4897,8 @@
"highlight.js": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=",
"dev": true
},
"hosted-git-info": {
"version": "2.7.1",
@@ -4965,7 +4960,8 @@
"humanize-plus": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/humanize-plus/-/humanize-plus-1.8.2.tgz",
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA="
"integrity": "sha1-pls0RZrWNnrbs3B6gqPJ+RYWcDA=",
"dev": true
},
"iconv-lite": {
"version": "0.4.23",
@@ -5604,12 +5600,6 @@
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
"integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
},
"is-promise": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz",
"integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=",
"dev": true
},
"is-proto-prop": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-1.0.1.tgz",
@@ -5750,14 +5740,14 @@
"dev": true
},
"jimp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.5.6.tgz",
"integrity": "sha512-H0nHTu6KgAgQzDxa38ew2dXbnRzKm1w5uEyhMIxqwCQVjwgarOjjkV/avbNLxfxRHAFaNp4rGIc/qm8P+uhX9A==",
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.6.0.tgz",
"integrity": "sha512-RYpN+AAlTEMf8Bnkhq2eeTNyr70rDK/2UUfUqzBJmwmZwdR6fxRJvgbCGWT1BDVRxaAqo+4CWm8ePBxOIsr4jg==",
"requires": {
"@babel/polyfill": "^7.0.0",
"@jimp/custom": "^0.5.4",
"@jimp/plugins": "^0.5.5",
"@jimp/types": "^0.5.4",
"@jimp/custom": "^0.6.0",
"@jimp/plugins": "^0.6.0",
"@jimp/types": "^0.6.0",
"core-js": "^2.5.7"
}
},
@@ -6417,11 +6407,18 @@
"integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw=="
},
"mime-types": {
"version": "2.1.20",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz",
"integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==",
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"requires": {
"mime-db": "~1.36.0"
"mime-db": "~1.37.0"
},
"dependencies": {
"mime-db": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
}
}
},
"mimic-fn": {
@@ -6531,19 +6528,19 @@
"dev": true
},
"mksnapshot": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/mksnapshot/-/mksnapshot-0.3.1.tgz",
"integrity": "sha1-JQHAVldDbXQs6Vik/5LHfkDdN+Y=",
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/mksnapshot/-/mksnapshot-0.3.4.tgz",
"integrity": "sha512-FgUTiWiY+35LgL95P/MDYrBuQO5o0s3MmaWKX6ZJWoX4vMOY9vPsAv763l1OSSelL9jPsBQ/wf4bzfqTLNPSFg==",
"dev": true,
"requires": {
"decompress-zip": "0.3.0",
"fs-extra": "0.26.7",
"request": "^2.79.0"
"request": "2.x"
},
"dependencies": {
"fs-extra": {
"version": "0.26.7",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
"resolved": "http://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz",
"integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=",
"dev": true,
"requires": {
@@ -6571,9 +6568,9 @@
"integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE="
},
"moment": {
"version": "2.22.2",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz",
"integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y="
"version": "2.23.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz",
"integrity": "sha512-3IE39bHVqFbWWaPOMHZF98Q9c3LDKGTmypMiTM2QygGXXElkFWIH7GxfmlwmY2vwa+wmNsoYZmG2iusf1ZjJoA=="
},
"mozjpeg": {
"version": "6.0.1",
@@ -7197,10 +7194,9 @@
"integrity": "sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA="
},
"node-abi": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.4.5.tgz",
"integrity": "sha512-aa/UC6Nr3+tqhHGRsAuw/edz7/q9nnetBrKWxj6rpTtm+0X9T1qU7lIEHMS3yN9JwAbRiKUbRRFy1PLz/y3aaA==",
"dev": true,
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.5.1.tgz",
"integrity": "sha512-oDbFc7vCFx0RWWCweTer3hFm1u+e60N5FtGnmRV6QqvgATGFH/XRR6vqWIeBVosCYCqt6YdIr2L0exLZuEdVcQ==",
"requires": {
"semver": "^5.4.1"
}
@@ -7275,16 +7271,6 @@
"resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
"integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
},
"nodeify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz",
"integrity": "sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0=",
"dev": true,
"requires": {
"is-promise": "~1.0.0",
"promise": "~1.3.0"
}
},
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
@@ -7770,9 +7756,9 @@
}
},
"pako": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
"integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.7.tgz",
"integrity": "sha512-3HNK5tW4x8o5mO8RuHZp3Ydw9icZXx0RANAOMzlMzx7LVXhMJ4mo3MOBpzyd7r/+RUu8BmndP47LXT+vzjtWcQ=="
},
"parse-author": {
"version": "2.0.0",
@@ -8030,26 +8016,20 @@
"integrity": "sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q=="
},
"plist": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/plist/-/plist-2.1.0.tgz",
"integrity": "sha1-V8zbeggh3yGDEhejytVOPhRqECU=",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
"integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==",
"dev": true,
"requires": {
"base64-js": "1.2.0",
"xmlbuilder": "8.2.2",
"base64-js": "^1.2.3",
"xmlbuilder": "^9.0.7",
"xmldom": "0.1.x"
},
"dependencies": {
"base64-js": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz",
"integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=",
"dev": true
},
"xmlbuilder": {
"version": "8.2.2",
"resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz",
"integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
"dev": true
}
}
@@ -8479,15 +8459,6 @@
}
}
},
"promise": {
"version": "1.3.0",
"resolved": "http://registry.npmjs.org/promise/-/promise-1.3.0.tgz",
"integrity": "sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU=",
"dev": true,
"requires": {
"is-promise": "~1"
}
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -8815,17 +8786,6 @@
}
}
},
"request-promise": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz",
"integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=",
"requires": {
"bluebird": "^3.5.0",
"request-promise-core": "1.1.1",
"stealthy-require": "^1.1.0",
"tough-cookie": ">=2.3.3"
}
},
"request-promise-core": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
@@ -9218,9 +9178,9 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-node-logger": {
"version": "0.93.40",
"resolved": "https://registry.npmjs.org/simple-node-logger/-/simple-node-logger-0.93.40.tgz",
"integrity": "sha512-ByWh6D6DgXteLICr5Bhca5CIDxuGt7xOysulWPIrBcwTT6ZCNF4SrwmtIDhC+cSNlJsz/fGytn7mH2Zqyh9euA==",
"version": "18.12.21",
"resolved": "https://registry.npmjs.org/simple-node-logger/-/simple-node-logger-18.12.21.tgz",
"integrity": "sha512-I2dA9JLiNrdTsmOI2bT0mIQNEKhTKbj9OM8tny3Il/5R6QdJHlWrv1NDdS+6UQHEnYV1413FnwgqTjzmV0ctCw==",
"requires": {
"lodash": "^4.17.10",
"moment": "^2.20.1"
@@ -10821,9 +10781,9 @@
}
},
"ws": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.0.tgz",
"integrity": "sha512-H3dGVdGvW2H8bnYpIDc3u3LH8Wue3Qh+Zto6aXXFzvESkTVT6rAfKR6tR/+coaUvxs8yHtmNV0uioBF62ZGSTg==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz",
"integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==",
"requires": {
"async-limiter": "~1.0.0"
}

View File

@@ -1,7 +1,8 @@
{
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.24.0-beta",
"version": "0.27.3",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -13,12 +14,9 @@
},
"scripts": {
"start": "node ./src/www",
"test-electron": "xo",
"rebuild-electron": "electron-rebuild",
"start-electron": "electron . --disable-gpu",
"build-electron": "electron-packager . --out=dist --asar --overwrite --platform=win32,linux --arch=ia32,x64 --app-version= --icon=src/public/app-icons/win/icon.ico",
"build-backend-docs": "jsdoc -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
"build-frontend-docs": "jsdoc -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
"build-backend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js",
"build-frontend-docs": "jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js",
"build-docs": "npm run build-backend-docs && npm run build-frontend-docs"
},
"dependencies": {
@@ -28,8 +26,7 @@
"cls-hooked": "4.2.2",
"commonmark": "0.28.1",
"cookie-parser": "1.4.3",
"debug": "4.1.0",
"devtron": "1.4.0",
"debug": "4.1.1",
"ejs": "2.6.1",
"electron-debug": "2.0.0",
"electron-dl": "1.12.0",
@@ -37,7 +34,7 @@
"express": "4.16.4",
"express-session": "1.15.6",
"fs-extra": "7.0.1",
"get-port": "4.0.0",
"get-port": "4.1.0",
"helmet": "3.15.0",
"html": "1.0.0",
"image-type": "3.0.0",
@@ -46,31 +43,32 @@
"imagemin-mozjpeg": "8.0.0",
"imagemin-pngquant": "6.0.0",
"ini": "1.3.5",
"jimp": "0.5.6",
"moment": "2.22.2",
"jimp": "0.6.0",
"mime-types": "^2.1.21",
"moment": "2.23.0",
"multer": "1.4.1",
"node-abi": "2.5.1",
"open": "0.0.5",
"rand-token": "0.4.0",
"rcedit": "1.1.1",
"request": "2.88.0",
"request-promise": "4.2.2",
"rimraf": "2.6.2",
"sanitize-filename": "1.6.1",
"sax": "^1.2.4",
"serve-favicon": "2.5.0",
"session-file-store": "1.2.0",
"simple-node-logger": "0.93.40",
"simple-node-logger": "18.12.21",
"sqlite": "3.0.0",
"tar-stream": "1.6.2",
"turndown": "5.0.1",
"unescape": "1.0.1",
"ws": "6.1.0",
"ws": "6.1.2",
"xml2js": "0.4.19"
},
"devDependencies": {
"electron": "4.0.0-beta.7",
"devtron": "1.4.0",
"electron": "4.0.1",
"electron-compile": "6.4.3",
"electron-packager": "12.2.0",
"electron-packager": "13.0.1",
"electron-rebuild": "1.8.2",
"lorem-ipsum": "1.0.6",
"tape": "4.9.1",

View File

@@ -105,6 +105,11 @@ class Attribute extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.isOwned;
}
}
module.exports = Attribute;

View File

@@ -59,6 +59,11 @@ class Branch extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
delete pojo.origParentNoteId;
}
}
module.exports = Branch;

View File

@@ -15,7 +15,8 @@ const ENTITY_NAME_TO_ENTITY = {
"note_revisions": NoteRevision,
"recent_notes": RecentNote,
"options": Option,
"api_tokens": ApiToken
"api_tokens": ApiToken,
"links": Link
};
function getEntityFromEntityName(entityName) {

View File

@@ -4,6 +4,7 @@ const Entity = require('./entity');
const Attribute = require('./attribute');
const protectedSessionService = require('../services/protected_session');
const repository = require('../services/repository');
const sql = require('../services/sql');
const dateUtils = require('../services/date_utils');
const LABEL = 'label';
@@ -74,7 +75,9 @@ class Note extends Entity {
/** @returns {boolean} true if this note is JavaScript (code or attachment) */
isJavaScript() {
return (this.type === "code" || this.type === "file")
&& (this.mime.startsWith("application/javascript") || this.mime === "application/x-javascript");
&& (this.mime.startsWith("application/javascript")
|| this.mime === "application/x-javascript"
|| this.mime === "text/javascript");
}
/** @returns {boolean} true if this note is HTML */
@@ -366,6 +369,16 @@ class Note extends Entity {
*/
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
/**
* @param {string} name
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
}
/**
* Based on enabled, label is either set or removed.
*
@@ -423,24 +436,32 @@ class Note extends Entity {
async removeRelation(name, value) { return await this.removeAttribute(RELATION, name, value); }
/**
* @param {string} name
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
* @return {Promise<string[]>} return list of all descendant noteIds of this note. Returning just noteIds because number of notes can be huge. Includes also this note's noteId
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
async getDescendantNoteIds() {
return await sql.getColumn(`
WITH RECURSIVE
tree(noteId) AS (
SELECT ?
UNION
SELECT branches.noteId FROM branches
JOIN tree ON branches.parentNoteId = tree.noteId
JOIN notes ON notes.noteId = branches.noteId
WHERE notes.isDeleted = 0
AND branches.isDeleted = 0
)
SELECT noteId FROM tree`, [this.noteId]);
}
/**
* Finds child notes with given attribute name and value. Only own attributes are considered, not inherited ones
* Finds descendant notes with given attribute name and value. Only own attributes are considered, not inherited ones
*
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @param {string} [value] - attribute value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithAttribute(type, name, value) {
async getDescendantNotesWithAttribute(type, name, value) {
const params = [this.noteId, name];
let valueCondition = "";
@@ -472,22 +493,22 @@ class Note extends Entity {
}
/**
* Finds notes with given label name and value. Only own labels are considered, not inherited ones
* Finds descendant notes with given label name and value. Only own labels are considered, not inherited ones
*
* @param {string} name - label name
* @param {string} [value] - label value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithLabel(name, value) { return await this.findChildNotesWithAttribute(LABEL, name, value); }
async getDescendantNotesWithLabel(name, value) { return await this.getDescendantNotesWithAttribute(LABEL, name, value); }
/**
* Finds notes with given relation name and value. Only own relations are considered, not inherited ones
* Finds descendant notes with given relation name and value. Only own relations are considered, not inherited ones
*
* @param {string} name - relation name
* @param {string} [value] - relation value
* @returns {Promise<Note[]>}
*/
async findChildNotesWithRelation(name, value) { return await this.findChildNotesWithAttribute(RELATION, name, value); }
async getDescendantNotesWithRelation(name, value) { return await this.getDescendantNotesWithAttribute(RELATION, name, value); }
/**
* Returns note revisions of this note.
@@ -587,10 +608,6 @@ class Note extends Entity {
// we do this here because encryption needs the note ID for the IV
this.generateIdIfNecessary();
if (this.isProtected) {
protectedSessionService.encryptNote(this);
}
if (!this.isDeleted) {
this.isDeleted = false;
}
@@ -605,6 +622,17 @@ class Note extends Entity {
this.dateModified = dateUtils.nowDate();
}
}
// cannot be static!
updatePojo(pojo) {
if (pojo.isProtected) {
protectedSessionService.encryptNote(pojo);
}
delete pojo.jsonContent;
delete pojo.isContentAvailable;
delete pojo.__attributeCache;
}
}
module.exports = Note;

Binary file not shown.

View File

@@ -0,0 +1,155 @@
import addLinkDialog from './dialogs/add_link.js';
import jumpToNoteDialog from './dialogs/jump_to_note.js';
import attributesDialog from './dialogs/attributes.js';
import noteRevisionsDialog from './dialogs/note_revisions.js';
import noteSourceDialog from './dialogs/note_source.js';
import recentChangesDialog from './dialogs/recent_changes.js';
import optionsDialog from './dialogs/options.js';
import sqlConsoleDialog from './dialogs/sql_console.js';
import markdownImportDialog from './dialogs/markdown_import.js';
import exportDialog from './dialogs/export.js';
import cloning from './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';
import noteType from './services/note_type.js';
import protected_session from './services/protected_session.js';
import searchNotesService from './services/search_notes.js';
import FrontendScriptApi from './services/frontend_script_api.js';
import ScriptContext from './services/script_context.js';
import sync from './services/sync.js';
import treeService from './services/tree.js';
import treeChanges from './services/branches.js';
import treeUtils from './services/tree_utils.js';
import utils from './services/utils.js';
import server from './services/server.js';
import entrypoints from './services/entrypoints.js';
import noteTooltipService from './services/note_tooltip.js';
import bundle from "./services/bundle.js";
import treeCache from "./services/tree_cache.js";
import libraryLoader from "./services/library_loader.js";
import hoistedNoteService from './services/hoisted_note.js';
import noteTypeService from './services/note_type.js';
import linkService from './services/link.js';
import noteAutocompleteService from './services/note_autocomplete.js';
// required for CKEditor image upload plugin
window.glob.getCurrentNode = treeService.getCurrentNode;
window.glob.getHeaders = server.getHeaders;
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
// this is required by CKEditor when uploading images
window.glob.noteChanged = noteDetailService.noteChanged;
window.glob.refreshTree = treeService.reload;
// required for ESLint plugin
window.glob.getCurrentNote = noteDetailService.getCurrentNote;
window.glob.requireLibrary = libraryLoader.requireLibrary;
window.glob.ESLINT = libraryLoader.ESLINT;
window.onerror = function (msg, url, lineNo, columnNo, error) {
const string = msg.toLowerCase();
let message = "Uncaught error: ";
if (string.includes("Cannot read property 'defaultView' of undefined")) {
// ignore this specific error which is very common but we don't know where it comes from
// and it seems to be harmless
return true;
}
else if (string.includes("script error")) {
message += 'No details available';
}
else {
message += [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
}
messagingService.logError(message);
return false;
};
const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/";
$(document).on("click", "button[data-help-page]", e => {
const $button = $(e.target);
window.open(wikiBaseUrl + $button.attr("data-help-page"), '_blank');
});
$("#logout-button").toggle(!utils.isElectron());
$("#tree").on("click", ".unhoist-button", hoistedNoteService.unhoist);
if (utils.isElectron()) {
require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
// this might occur when day note had to be created
if (!await treeCache.getNote(parentNoteId)) {
await treeService.reload();
}
await treeService.activateNote(parentNoteId);
setTimeout(async () => {
const parentNode = treeService.getCurrentNode();
const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', parentNode.data.isProtected);
await treeService.activateNote(note.noteId);
}, 500);
});
}
function exec(cmd) {
document.execCommand(cmd);
return false;
}
if (utils.isElectron() && utils.isMac()) {
utils.bindShortcut('ctrl+c', () => exec("copy"));
utils.bindShortcut('ctrl+v', () => exec('paste'));
utils.bindShortcut('ctrl+x', () => exec('cut'));
utils.bindShortcut('ctrl+a', () => exec('selectAll'));
utils.bindShortcut('ctrl+z', () => exec('undo'));
utils.bindShortcut('ctrl+y', () => exec('redo'));
utils.bindShortcut('meta+c', () => exec("copy"));
utils.bindShortcut('meta+v', () => exec('paste'));
utils.bindShortcut('meta+x', () => exec('cut'));
utils.bindShortcut('meta+a', () => exec('selectAll'));
utils.bindShortcut('meta+z', () => exec('undo'));
utils.bindShortcut('meta+y', () => exec('redo'));
}
$("#export-note-button").click(function () {
if ($(this).hasClass("disabled")) {
return;
}
exportDialog.showDialog('single');
});
treeService.showTree();
entrypoints.registerEntrypoints();
noteTooltipService.setupGlobalTooltip();
bundle.executeStartupBundles();
noteTypeService.init();
linkService.init();
noteAutocompleteService.init();

View File

@@ -67,12 +67,13 @@ function AttributesModel() {
attr.labelDefinition = (attr.type === 'label-definition' && attr.value) ? attr.value : {
labelType: "text",
multiplicityType: "singlevalue",
isPromoted: true
isPromoted: true,
numberPrecision: 0
};
attr.relationDefinition = (attr.type === 'relation-definition' && attr.value) ? attr.value : {
multiplicityType: "singlevalue",
mirrorRelation: "",
inverseRelation: "",
isPromoted: true
};
@@ -114,7 +115,7 @@ function AttributesModel() {
function isValid() {
for (let attributes = self.ownedAttributes(), i = 0; i < attributes.length; i++) {
if (self.isEmptyName(i)) {
if (self.isEmptyName(i) || self.isEmptyRelationTarget(i)) {
return false;
}
}
@@ -168,6 +169,8 @@ function AttributesModel() {
infoService.showMessage("Attributes have been saved.");
attributeService.refreshAttributes();
noteDetailService.reload();
};
function addLastEmptyRow() {
@@ -187,11 +190,12 @@ function AttributesModel() {
labelDefinition: {
labelType: "text",
multiplicityType: "singlevalue",
isPromoted: true
isPromoted: true,
numberPrecision: 0
},
relationDefinition: {
multiplicityType: "singlevalue",
mirrorRelation: "",
inverseRelation: "",
isPromoted: true
}
}));
@@ -209,7 +213,35 @@ function AttributesModel() {
this.isEmptyName = function(index) {
const cur = self.ownedAttributes()[index]();
return cur.name.trim() === "" && !cur.isDeleted && (cur.attributeId !== "" || cur.labelValue !== "" || cur.relationValue);
if (cur.name.trim() || cur.isDeleted) {
return false;
}
if (cur.attributeId) {
// name is empty and attribute already exists so this is NO-GO
return true;
}
if (cur.type === 'relation-definition' || cur.type === 'label-definition') {
// for definitions there's no possible empty value so we always require name
return true;
}
if (cur.type === 'label' && cur.labelValue) {
return true;
}
if (cur.type === 'relation' && cur.relationValue) {
return true;
}
return false;
};
this.isEmptyRelationTarget = function(index) {
const cur = self.ownedAttributes()[index]();
return cur.type === "relation" && !cur.isDeleted && cur.name && !cur.relationValue;
};
this.getTargetAttribute = function(target) {

View File

@@ -2,6 +2,7 @@ import treeService from '../services/tree.js';
import server from '../services/server.js';
import treeCache from "../services/tree_cache.js";
import treeUtils from "../services/tree_utils.js";
import infoService from "../services/info.js";
const $dialog = $("#branch-prefix-dialog");
const $form = $("#branch-prefix-form");
@@ -24,7 +25,7 @@ async function showDialog() {
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
$noteTitle.text(" - " + noteTitle);
}
async function savePrefix() {
@@ -35,6 +36,8 @@ async function savePrefix() {
await treeService.setPrefix(branchId, prefix);
$dialog.modal('hide');
infoService.showMessage("Branch prefix has been saved.");
}
$form.submit(() => {

View File

@@ -0,0 +1,77 @@
import treeService from '../services/tree.js';
import treeUtils from "../services/tree_utils.js";
import exportService from "../services/export.js";
const $dialog = $("#export-dialog");
const $form = $("#export-form");
const $noteTitle = $dialog.find(".note-title");
const $subtreeFormats = $("#export-subtree-formats");
const $singleFormats = $("#export-single-formats");
const $subtreeType = $("#export-type-subtree");
const $singleType = $("#export-type-single");
async function showDialog(defaultType) {
if (defaultType === 'subtree') {
$subtreeType.prop("checked", true).change();
}
else if (defaultType === 'single') {
$singleType.prop("checked", true).change();
}
else {
throw new Error("Unrecognized type " + defaultType);
}
glob.activeDialog = $dialog;
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
}
$form.submit(() => {
const exportType = $dialog.find("input[name='export-type']:checked").val();
if (!exportType) {
// this shouldn't happen as we always choose default export type
alert("Choose export type first please");
return;
}
const exportFormat = exportType === 'subtree'
? $("input[name=export-subtree-format]:checked").val()
: $("input[name=export-single-format]:checked").val();
const currentNode = treeService.getCurrentNode();
exportService.exportBranch(currentNode.data.branchId, exportType, exportFormat);
$dialog.modal('hide');
return false;
});
$('input[name=export-type]').change(function () {
if (this.value === 'subtree') {
if ($("input[name=export-subtree-format]:checked").length === 0) {
$("input[name=export-subtree-format]:first").prop("checked", true);
}
$subtreeFormats.slideDown();
$singleFormats.slideUp();
}
else {
if ($("input[name=export-single-format]:checked").length === 0) {
$("input[name=export-single-format]:first").prop("checked", true);
}
$subtreeFormats.slideUp();
$singleFormats.slideDown();
}
});
export default {
showDialog
};

View File

@@ -1,35 +0,0 @@
import treeService from '../services/tree.js';
import server from '../services/server.js';
import treeUtils from "../services/tree_utils.js";
import exportService from "../services/export.js";
const $dialog = $("#export-subtree-dialog");
const $form = $("#export-subtree-form");
const $noteTitle = $dialog.find(".note-title");
async function showDialog() {
glob.activeDialog = $dialog;
$dialog.modal();
const currentNode = treeService.getCurrentNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
$noteTitle.html(noteTitle);
}
$form.submit(() => {
const exportFormat = $dialog.find("input[name='export-format']:checked").val();
const currentNode = treeService.getCurrentNode();
exportService.exportSubtree(currentNode.data.branchId, exportFormat);
$dialog.modal('hide');
return false;
});
export default {
showDialog
};

View File

@@ -198,15 +198,17 @@ addTabHandler((async function () {
const $syncVersion = $("#sync-version");
const $buildDate = $("#build-date");
const $buildRevision = $("#build-revision");
const $dataDirectory = $("#data-directory");
const appInfo = await server.get('app-info');
$appVersion.html(appInfo.appVersion);
$dbVersion.html(appInfo.dbVersion);
$syncVersion.html(appInfo.syncVersion);
$buildDate.html(appInfo.buildDate);
$buildRevision.html(appInfo.buildRevision);
$appVersion.text(appInfo.appVersion);
$dbVersion.text(appInfo.dbVersion);
$syncVersion.text(appInfo.syncVersion);
$buildDate.text(appInfo.buildDate);
$buildRevision.text(appInfo.buildRevision);
$buildRevision.attr('href', 'https://github.com/zadam/trilium/commit/' + appInfo.buildRevision);
$dataDirectory.text(appInfo.dataDirectory);
return {};
})());

View File

@@ -1,6 +1,9 @@
const $dialog = $("#prompt-dialog");
const $question = $("#prompt-dialog-question");
const $answer = $("#prompt-dialog-answer");
const $dialogBody = $dialog.find(".modal-body");
let $question;
let $answer;
const $form = $("#prompt-dialog-form");
let resolve;
@@ -11,8 +14,21 @@ function ask({ message, defaultValue, shown }) {
shownCb = shown;
$question.text(message);
$answer.val(defaultValue || "");
$question = $("<label>")
.prop("for", "prompt-dialog-answer")
.text(message);
$answer = $("<input>")
.prop("type", "text")
.prop("id", "prompt-dialog-answer")
.addClass("form-control")
.val(defaultValue || "");
$dialogBody.empty().append(
$("<div>")
.addClass("form-group")
.append($question)
.append($answer));
$dialog.modal();

View File

@@ -50,7 +50,12 @@ async function execute(e) {
e.preventDefault();
e.stopPropagation();
const sqlQuery = codeEditor.getValue();
// execute the selected text or the whole content if there's no selection
let sqlQuery = codeEditor.getSelection();
if (!sqlQuery) {
sqlQuery = codeEditor.getValue();
}
const result = await server.post("sql/execute", {
query: sqlQuery

View File

@@ -0,0 +1,36 @@
class Attribute {
constructor(treeCache, row) {
this.treeCache = treeCache;
/** @param {string} attributeId */
this.attributeId = row.attributeId;
/** @param {string} noteId */
this.noteId = row.noteId;
/** @param {string} type */
this.type = row.type;
/** @param {string} name */
this.name = row.name;
/** @param {string} value */
this.value = row.value;
/** @param {int} position */
this.position = row.position;
/** @param {boolean} isInheritable */
this.isInheritable = row.isInheritable;
/** @param {boolean} isDeleted */
this.isDeleted = row.isDeleted;
/** @param {string} dateCreated */
this.dateCreated = row.dateCreated;
/** @param {string} dateModified */
this.dateModified = row.dateModified;
}
/** @returns {NoteShort} */
async getNote() {
return await this.treeCache.getNote(this.noteId);
}
get toString() {
return `Attribute(attributeId=${this.attributeId}, type=${this.type}, name=${this.name})`;
}
}
export default Attribute;

View File

@@ -14,7 +14,7 @@ class Branch {
/** @param {string} */
this.prefix = row.prefix;
/** @param {boolean} */
this.isExpanded = row.isExpanded;
this.isExpanded = !!row.isExpanded;
}
/** @returns {NoteShort} */

View File

@@ -1,3 +1,10 @@
import server from '../services/server.js';
const LABEL = 'label';
const LABEL_DEFINITION = 'label-definition';
const RELATION = 'relation';
const RELATION_DEFINITION = 'relation-definition';
/**
* This note's representation is used in note tree and is kept in TreeCache.
* Its notable omission is the note content.
@@ -71,6 +78,140 @@ class NoteShort {
return await this.treeCache.getNotes(this.getChildNoteIds());
}
/**
* @param {string} [name] - attribute name to filter
* @returns {Promise<Attribute[]>}
*/
async getAttributes(name) {
if (!this.attributeCache) {
this.attributeCache = await server.get('notes/' + this.noteId + '/attributes');
}
if (name) {
return this.attributeCache.filter(attr => attr.name === name);
}
else {
return this.attributeCache;
}
}
/**
* @param {string} [name] - label name to filter
* @returns {Promise<Attribute[]>} all note's labels (attributes with type label), including inherited ones
*/
async getLabels(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL);
}
/**
* @param {string} [name] - label name to filter
* @returns {Promise<Attribute[]>} all note's label definitions, including inherited ones
*/
async getLabelDefinitions(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === LABEL_DEFINITION);
}
/**
* @param {string} [name] - relation name to filter
* @returns {Promise<Attribute[]>} all note's relations (attributes with type relation), including inherited ones
*/
async getRelations(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION);
}
/**
* @param {string} [name] - relation name to filter
* @returns {Promise<Attribute[]>} all note's relation definitions including inherited ones
*/
async getRelationDefinitions(name) {
return (await this.getAttributes(name)).filter(attr => attr.type === RELATION_DEFINITION);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise<boolean>} true if note has an attribute with given type and name (including inherited)
*/
async hasAttribute(type, name) {
return !!await this.getAttribute(type, name);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise<Attribute>} attribute of given type and name. If there's more such attributes, first is returned. Returns null if there's no such attribute belonging to this note.
*/
async getAttribute(type, name) {
const attributes = await this.getAttributes();
return attributes.find(attr => attr.type === type && attr.name === name);
}
/**
* @param {string} type - attribute type (label, relation, etc.)
* @param {string} name - attribute name
* @returns {Promise<string>} attribute value of given type and name or null if no such attribute exists.
*/
async getAttributeValue(type, name) {
const attr = await this.getAttribute(type, name);
return attr ? attr.value : null;
}
/**
* @param {string} name - label name
* @returns {Promise<boolean>} true if label exists (including inherited)
*/
async hasLabel(name) { return await this.hasAttribute(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise<boolean>} true if relation exists (including inherited)
*/
async hasRelation(name) { return await this.hasAttribute(RELATION, name); }
/**
* @param {string} name - label name
* @returns {Promise<Attribute>} label if it exists, null otherwise
*/
async getLabel(name) { return await this.getAttribute(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise<Attribute>} relation if it exists, null otherwise
*/
async getRelation(name) { return await this.getAttribute(RELATION, name); }
/**
* @param {string} name - label name
* @returns {Promise<string>} label value if label exists, null otherwise
*/
async getLabelValue(name) { return await this.getAttributeValue(LABEL, name); }
/**
* @param {string} name - relation name
* @returns {Promise<string>} relation value if relation exists, null otherwise
*/
async getRelationValue(name) { return await this.getAttributeValue(RELATION, name); }
/**
* @param {string} name
* @returns {Promise<Note>|null} target note of the relation or null (if target is empty or note was not found)
*/
async getRelationTarget(name) {
const relation = await this.getRelation(name);
return relation ? await repository.getNote(relation.value) : null;
}
/**
* Clear note's attributes cache to force fresh reload for next attribute request.
* Cache is note instance scoped.
*/
invalidateAttributeCache() {
this.attributeCache = null;
}
get toString() {
return `Note(noteId=${this.noteId}, title=${this.title})`;
}
@@ -79,6 +220,7 @@ class NoteShort {
const dto = Object.assign({}, this);
delete dto.treeCache;
delete dto.archived;
delete dto.attributeCache;
return dto;
}

View File

@@ -0,0 +1,128 @@
import treeService from "./services/tree.js";
import noteDetailService from "./services/note_detail.js";
import dragAndDropSetup from "./services/drag_and_drop.js";
import treeCache from "./services/tree_cache.js";
import treeBuilder from "./services/tree_builder.js";
import contextMenuWidget from "./services/context_menu.js";
import ContextMenuItemsContainer from "./services/context_menu_items_container.js";
import treeChangesService from "./services/branches.js";
import utils from "./services/utils.js";
import treeUtils from "./services/tree_utils.js";
const $leftPane = $("#left-pane");
const $tree = $("#tree");
const $detail = $("#detail");
const $closeDetailButton = $("#close-detail-button");
function togglePanes() {
if (!$leftPane.is(":visible") || !$detail.is(":visible")) {
$detail.toggleClass("d-none");
$leftPane.toggleClass("d-none");
}
}
function showDetailPane() {
if (!$detail.is(":visible")) {
$detail.removeClass("d-none");
$leftPane.addClass("d-none");
}
}
$closeDetailButton.click(() => {
// no page is opened
document.location.hash = '-';
togglePanes();
});
async function showTree() {
const tree = await treeService.loadTree();
$tree.fancytree({
autoScroll: true,
extensions: ["dnd5", "clones"],
source: tree,
scrollParent: $tree,
minExpandLevel: 2, // root can't be collapsed
activate: (event, data) => {
const node = data.node;
const noteId = node.data.noteId;
treeService.clearSelectedNodes();
treeService.setCurrentNotePathToHash(node);
showDetailPane();
noteDetailService.switchToNote(noteId, true);
},
expand: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, true),
collapse: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, false),
init: (event, data) => treeService.treeInitialized(), // don't collapse to short form
dnd5: dragAndDropSetup,
lazyLoad: function(event, data) {
const noteId = data.node.data.noteId;
data.result = treeCache.getNote(noteId).then(note => treeBuilder.prepareBranch(note));
},
clones: {
highlightActiveClones: true
}
});
}
$("#note-menu-button").click(async e => {
const node = treeService.getCurrentNode();
const branch = await treeCache.getBranch(node.data.branchId);
const note = await treeCache.getNote(node.data.noteId);
const parentNote = await treeCache.getNote(branch.parentNoteId);
const isNotRoot = note.noteId !== 'root';
const itemsContainer = new ContextMenuItemsContainer([
{title: "Insert note after", cmd: "insertNoteAfter", uiIcon: "plus"},
{title: "Insert child note", cmd: "insertChildNote", uiIcon: "plus"},
{title: "Delete this note", cmd: "delete", uiIcon: "trash"}
]);
itemsContainer.enableItem("insertNoteAfter", isNotRoot && parentNote.type !== 'search');
itemsContainer.enableItem("insertChildNote", note.type !== 'search');
itemsContainer.enableItem("delete", isNotRoot && parentNote.type !== 'search');
contextMenuWidget.initContextMenu(e, itemsContainer, (event, cmd) => {
if (cmd === "insertNoteAfter") {
const parentNoteId = node.data.parentNoteId;
const isProtected = treeUtils.getParentProtectedStatus(node);
treeService.createNote(node, parentNoteId, 'after', isProtected);
}
else if (cmd === "insertChildNote") {
treeService.createNote(node, node.data.noteId, 'into');
}
else if (cmd === "delete") {
treeChangesService.deleteNodes([node]);
// move to the tree
togglePanes();
}
else {
throw new Error("Unrecognized command " + cmd);
}
});
});
$("#switch-to-desktop-button").click(() => {
utils.setCookie('trilium-device', 'desktop');
utils.reloadApp();
});
$("#log-out-button").click(() => {
$("#logout-form").submit();
});
// this is done so that startNotePath is not used
if (!document.location.hash) {
document.location.hash = '-';
}
showTree();

View File

@@ -10,11 +10,13 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
$el.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'name',
// disabling cache is important here because otherwise cache can stay intact when switching between attribute type which will lead to autocomplete displaying attribute names for incorrect attribute type
cache: false,
source: async (term, cb) => {
const type = typeof attributeType === "function" ? attributeType() : attributeType;
@@ -23,10 +25,6 @@ function initAttributeNameAutocomplete({ $el, attributeType, open }) {
return {name};
});
if (result.length === 0) {
result.push({name: "No results"});
}
cb(result);
}
}]);
@@ -55,9 +53,9 @@ async function initLabelValueAutocomplete({ $el, open }) {
$el.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {

View File

@@ -3,24 +3,35 @@ import utils from "./utils.js";
import messagingService from "./messaging.js";
import treeUtils from "./tree_utils.js";
import noteAutocompleteService from "./note_autocomplete.js";
import treeService from "./tree.js";
import linkService from "./link.js";
import infoService from "./info.js";
import noteDetailService from "./note_detail.js";
const $attributeList = $("#attribute-list");
const $attributeListInner = $("#attribute-list-inner");
const $promotedAttributesContainer = $("#note-detail-promoted-attributes");
const $savedIndicator = $("#saved-indicator");
let attributePromise;
async function refreshAttributes() {
function invalidateAttributes() {
attributePromise = null;
}
function reloadAttributes() {
attributePromise = server.get('notes/' + noteDetailService.getCurrentNoteId() + '/attributes');
}
async function refreshAttributes() {
reloadAttributes();
await showAttributes();
}
async function getAttributes() {
if (!attributePromise) {
reloadAttributes();
}
return await attributePromise;
}
@@ -74,8 +85,11 @@ async function showAttributes() {
$promotedAttributesContainer.empty().append($tbody);
}
else if (note.type !== 'relation-map') {
if (attributes.length > 0) {
for (const attribute of attributes) {
// display only "own" notes
const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
if (ownedAttributes.length > 0) {
for (const attribute of ownedAttributes) {
if (attribute.type === 'label') {
$attributeListInner.append(utils.formatLabel(attribute) + " ");
}
@@ -121,7 +135,9 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
const $actionCell = $("<td>");
const $multiplicityCell = $("<td>").addClass("multiplicity");
const $multiplicityCell = $("<td>")
.addClass("multiplicity")
.attr("nowrap", true);
$tr
.append($labelCell)
@@ -146,7 +162,8 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [{
displayKey: 'value',
source: function (term, cb) {
@@ -161,6 +178,14 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
}
else if (definition.labelType === 'number') {
$input.prop("type", "number");
let step = 1;
for (let i = 0; i < (definition.numberPrecision || 0) && i < 10; i++) {
step /= 10;
}
$input.prop("step", step);
}
else if (definition.labelType === 'boolean') {
$input.prop("type", "checkbox");
@@ -267,11 +292,17 @@ async function promotedAttributeChanged(event) {
$attr.prop("attribute-id", result.attributeId);
infoService.showMessage("Attribute has been saved.");
// animate only if it's not being animated already, this is important especially for e.g. number inputs
// which can be changed many times in a second by clicking on higher/lower buttons.
if ($savedIndicator.queue().length === 0) {
$savedIndicator.fadeOut();
$savedIndicator.fadeIn();
}
}
export default {
getAttributes,
showAttributes,
refreshAttributes
refreshAttributes,
invalidateAttributes
}

View File

@@ -1,114 +0,0 @@
import addLinkDialog from '../dialogs/add_link.js';
import jumpToNoteDialog from '../dialogs/jump_to_note.js';
import attributesDialog from '../dialogs/attributes.js';
import noteRevisionsDialog from '../dialogs/note_revisions.js';
import noteSourceDialog from '../dialogs/note_source.js';
import recentChangesDialog from '../dialogs/recent_changes.js';
import optionsDialog from '../dialogs/options.js';
import sqlConsoleDialog from '../dialogs/sql_console.js';
import markdownImportDialog from '../dialogs/markdown_import.js';
import cloning from './cloning.js';
import contextMenu from './tree_context_menu.js';
import dragAndDropSetup from './drag_and_drop.js';
import exportService from './export.js';
import link from './link.js';
import messagingService from './messaging.js';
import noteDetailService from './note_detail.js';
import noteType from './note_type.js';
import protected_session from './protected_session.js';
import searchNotesService from './search_notes.js';
import FrontendScriptApi from './frontend_script_api.js';
import ScriptContext from './script_context.js';
import sync from './sync.js';
import treeService from './tree.js';
import treeChanges from './branches.js';
import treeUtils from './tree_utils.js';
import utils from './utils.js';
import server from './server.js';
import entrypoints from './entrypoints.js';
import tooltip from './tooltip.js';
import bundle from "./bundle.js";
import treeCache from "./tree_cache.js";
import libraryLoader from "./library_loader.js";
// required for CKEditor image upload plugin
window.glob.getCurrentNode = treeService.getCurrentNode;
window.glob.getHeaders = server.getHeaders;
window.glob.showAddLinkDialog = addLinkDialog.showDialog;
// this is required by CKEditor when uploading images
window.glob.noteChanged = noteDetailService.noteChanged;
window.glob.refreshTree = treeService.reload;
// required for ESLint plugin
window.glob.getCurrentNote = noteDetailService.getCurrentNote;
window.glob.requireLibrary = libraryLoader.requireLibrary;
window.glob.ESLINT = libraryLoader.ESLINT;
window.onerror = function (msg, url, lineNo, columnNo, error) {
const string = msg.toLowerCase();
let message = "Uncaught error: ";
if (string.includes("Cannot read property 'defaultView' of undefined")) {
// ignore this specific error which is very common but we don't know where it comes from
// and it seems to be harmless
return true;
}
else if (string.includes("script error")) {
message += 'No details available';
}
else {
message += [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
}
messagingService.logError(message);
return false;
};
const wikiBaseUrl = "https://github.com/zadam/trilium/wiki/";
$(document).on("click", "button[data-help-page]", e => {
const $button = $(e.target);
window.open(wikiBaseUrl + $button.attr("data-help-page"), '_blank');
});
$("#logout-button").toggle(!utils.isElectron());
if (utils.isElectron()) {
require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
// this might occur when day note had to be created
if (!await treeCache.getNote(parentNoteId)) {
await treeService.reload();
}
await treeService.activateNote(parentNoteId);
setTimeout(async () => {
const parentNode = treeService.getCurrentNode();
const {note} = await treeService.createNote(parentNode, parentNode.data.noteId, 'into', parentNode.data.isProtected);
await treeService.activateNote(note.noteId);
}, 500);
});
}
$("#export-note-to-markdown-button").click(() => exportService.exportSubtree(noteDetailService.getCurrentNoteId(), 'markdown-single'));
treeService.showTree();
entrypoints.registerEntrypoints();
tooltip.setupTooltip();
bundle.executeStartupBundles();

View File

@@ -1,9 +1,11 @@
const $contextMenuContainer = $("#context-menu-container");
function initContextMenu(event, contextMenuItems, selectContextMenuItem) {
function initContextMenu(event, itemContainer, selectContextMenuItem) {
event.stopPropagation();
$contextMenuContainer.empty();
for (const item of contextMenuItems) {
for (const item of itemContainer.getItems()) {
if (item.title === '----') {
$contextMenuContainer.append($("<div>").addClass("dropdown-divider"));
} else {

View File

@@ -0,0 +1,28 @@
class ContextMenuItemsContainer {
constructor(items) {
// clone the item array and the items themselves
this.items = items.map(item => Object.assign({}, item));
}
hideItem(cmd, hidden = true) {
if (hidden) {
this.items = this.items.filter(item => item.cmd !== cmd);
}
}
enableItem(cmd, enabled) {
const item = this.items.find(item => item.cmd === cmd);
if (!item) {
throw new Error(`Command ${cmd} has not been found!`);
}
item.enabled = enabled;
}
getItems() {
return this.items;
}
}
export default ContextMenuItemsContainer;

View File

@@ -4,31 +4,26 @@ import treeChangesService from './branches.js';
const dragAndDropSetup = {
autoExpandMS: 600,
dragStart: (node, data) => {
// don't allow dragging root node
if (node.data.noteId === 'root') {
return false;
}
node.setSelected(true);
const selectedNodes = treeService.getSelectedNodes().map(node => {
return {
noteId: node.data.noteId,
title: node.title
}
});
// this is for dragging notes into relation map
data.dataTransfer.setData("text", JSON.stringify(selectedNodes));
// we allow to drag only one note at a time because it multi-drag conflicts with multiple single drags
// in UX and single drag is probably more useful
data.dataTransfer.setData("text", JSON.stringify({
noteId: node.data.noteId,
title: node.title
}));
// This function MUST be defined to enable dragging for the tree.
// Return false to cancel dragging of node.
return true;
},
dragEnter: (node, data) => {
// we don't allow moving root to any other location in the tree
// we allow it to be placed on the relation map though, that's handled in a different drop handler
return node.data.noteId === 'root';
}, // allow drop on any node
dragEnter: (node, data) => true, // allow drop on any node
dragDrop: (node, data) => {
// This function MUST be defined to enable dropping of items on the tree.
// data.hitMode is 'before', 'after', or 'over'.

View File

@@ -25,14 +25,26 @@ function registerEntrypoints() {
$("#jump-to-note-dialog-button").click(jumpToNoteDialog.showDialog);
utils.bindShortcut('ctrl+j', jumpToNoteDialog.showDialog);
$("#show-note-revisions-button").click(noteRevisionsDialog.showCurrentNoteRevisions);
$("#show-note-revisions-button").click(function() {
if ($(this).hasClass("disabled")) {
return;
}
$("#show-source-button").click(noteSourceDialog.showDialog);
noteRevisionsDialog.showCurrentNoteRevisions();
});
$("#show-source-button").click(function() {
if ($(this).hasClass("disabled")) {
return;
}
noteSourceDialog.showDialog();
});
$("#recent-changes-button").click(recentChangesDialog.showDialog);
$("#protected-session-on").click(protectedSessionService.enterProtectedSession);
$("#protected-session-off").click(protectedSessionService.leaveProtectedSession);
$("#enter-protected-session-button").click(protectedSessionService.enterProtectedSession);
$("#leave-protected-session-button").click(protectedSessionService.leaveProtectedSession);
$("#toggle-search-button").click(searchNotesService.toggleSearch);
utils.bindShortcut('ctrl+s', searchNotesService.toggleSearch);
@@ -83,18 +95,31 @@ function registerEntrypoints() {
}
});
$(document).bind('keydown', 'ctrl+f', () => {
function openInPageSearch() {
if (utils.isElectron()) {
const searchInPage = require('electron-in-page-search').default;
const remote = require('electron').remote;
const $searchWindowWebview = $(".electron-in-page-search-window");
$searchWindowWebview.show();
const inPageSearch = searchInPage(remote.getCurrentWebContents());
const searchInPage = require('electron-in-page-search').default;
const {remote} = require('electron');
const inPageSearch = searchInPage(remote.getCurrentWebContents(), {
searchWindowWebview: $searchWindowWebview[0],
//openDevToolsOfSearchWindow: true,
customCssPath: '/libraries/electron-in-page-search/default-style.css'
});
inPageSearch.openSearchWindow();
return false;
}
});
}
utils.bindShortcut('ctrl+f', openInPageSearch);
if (utils.isMac()) {
utils.bindShortcut('meta+f', openInPageSearch);
}
// FIXME: do we really need these at this point?
utils.bindShortcut("ctrl+shift+up", () => {

View File

@@ -1,16 +1,14 @@
import treeService from './tree.js';
import infoService from './info.js';
import protectedSessionHolder from './protected_session_holder.js';
import utils from './utils.js';
import server from './server.js';
function exportSubtree(noteId, format) {
const url = utils.getHost() + "/api/notes/" + noteId + "/export/" + format +
"?protectedSessionId=" + encodeURIComponent(protectedSessionHolder.getProtectedSessionId());
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);
infoService.showMessage("Export to file has been finished.");
}
let importNoteId;
@@ -47,6 +45,6 @@ $("#import-upload").change(async function() {
});
export default {
exportSubtree,
exportBranch,
importIntoNote
};

View File

@@ -6,6 +6,8 @@ import linkService from './link.js';
import treeCache from './tree_cache.js';
import noteDetailService from './note_detail.js';
import noteTypeService from './note_type.js';
import noteTooltipService from './note_tooltip.js';
import protectedSessionService from'./protected_session.js';
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@@ -41,7 +43,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
this.activateNewNote = async notePath => {
await treeService.reload();
await treeService.activateNote(notePath, true);
await treeService.activateNote(notePath, noteDetailService.focusOnTitle);
};
/**
@@ -202,6 +204,19 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
*/
this.getCurrentNoteContent = noteDetailService.getCurrentNoteContent;
/**
* 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.isNoteStillLoaded = () => {
return this.originEntity.noteId === noteDetailService.getCurrentNoteId();
};
/**
* @method
* @param {function} func - callback called on note change as user is typing (not necessarily tied to save event)
@@ -225,6 +240,17 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
* @param {array} types - list of mime types to be used
*/
this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes;
/**
* @method
* @param {object} $el - jquery object on which to setup the tooltip
*/
this.setupElementTooltip = noteTooltipService.setupElementTooltip;
/**
* @method
*/
this.protectCurrentNote = protectedSessionService.protectNoteAndSendToServer;
}
export default FrontendScriptApi;

View File

@@ -0,0 +1,33 @@
import optionsInit from './options_init.js';
import server from "./server.js";
import tree from "./tree.js";
let hoistedNoteId;
optionsInit.optionsReady.then(options => {
hoistedNoteId = options['hoistedNoteId'];
});
async function getHoistedNoteId() {
await optionsInit.optionsReady;
return hoistedNoteId;
}
async function setHoistedNoteId(noteId) {
hoistedNoteId = noteId;
await server.put('options/hoistedNoteId/' + noteId);
await tree.reload();
}
async function unhoist() {
await setHoistedNoteId('root');
}
export default {
getHoistedNoteId,
setHoistedNoteId,
unhoist
}

View File

@@ -5,13 +5,9 @@ function showMessage(message) {
console.debug(utils.now(), "message: ", message);
$.notify({
// options
icon: 'jam jam-check',
message: message
}, {
// options
type: 'success',
delay: 3000
});
}, getNotifySettings('success', 3000));
}
function showAndLogError(message, delay = 10000) {
@@ -25,12 +21,26 @@ function showError(message, delay = 10000) {
$.notify({
// options
icon: 'jam jam-alert',
message: message
}, {
// options
type: 'danger',
}, getNotifySettings('danger', delay));
}
function getNotifySettings(type, delay) {
return {
element: 'body',
type: type,
z_index: 90000,
placement: {
from: "top",
align: "center"
},
animate: {
enter: 'animated fadeInDown',
exit: 'animated fadeOutUp'
},
delay: delay
});
};
}
function throwError(message) {

View File

@@ -88,17 +88,19 @@ function addTextToEditor(text) {
});
}
ko.bindingHandlers.noteLink = {
init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) {
const noteId = ko.unwrap(valueAccessor());
function init() {
ko.bindingHandlers.noteLink = {
init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) {
const noteId = ko.unwrap(valueAccessor());
if (noteId) {
const link = await createNoteLink(noteId);
if (noteId) {
const link = await createNoteLink(noteId);
$(element).append(link);
$(element).append(link);
}
}
}
};
};
}
// when click on link popup, in case of internal link, just go the the referenced note instead of default behavior
// of opening the link in new window/tab
@@ -124,5 +126,6 @@ export default {
getNotePathFromUrl,
createNoteLink,
addLinkToEditor,
addTextToEditor
addTextToEditor,
init
};

View File

@@ -76,7 +76,8 @@ function initNoteAutocomplete($el, options) {
hint: false,
autoselect: true,
openOnFocus: true,
minLength: 0
minLength: 0,
tabAutocomplete: false
}, [
{
source: autocompleteSource,
@@ -92,7 +93,7 @@ function initNoteAutocomplete($el, options) {
$el.on('autocomplete:selected', (event, suggestion) => $el.setSelectedPath(suggestion.path));
$el.on('autocomplete:closed', () => {
if (!$el.val().trim()) {
$el.setSelectedPath("");
clearText($el);
}
});
}
@@ -100,40 +101,42 @@ function initNoteAutocomplete($el, options) {
return $el;
}
$.fn.getSelectedPath = function() {
if (!$(this).val().trim()) {
return "";
}
else {
return $(this).attr(SELECTED_PATH_KEY);
}
};
function init() {
$.fn.getSelectedPath = function () {
if (!$(this).val().trim()) {
return "";
} else {
return $(this).attr(SELECTED_PATH_KEY);
}
};
$.fn.setSelectedPath = function(path) {
path = path || "";
$.fn.setSelectedPath = function (path) {
path = path || "";
$(this).attr(SELECTED_PATH_KEY, path);
$(this).attr(SELECTED_PATH_KEY, path);
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", !path.trim())
.attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed
};
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", !path.trim())
.attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed
};
ko.bindingHandlers.noteAutocomplete = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
initNoteAutocomplete($(element));
ko.bindingHandlers.noteAutocomplete = {
init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
initNoteAutocomplete($(element));
$(element).setSelectedPath(bindingContext.$data.selectedPath);
$(element).setSelectedPath(bindingContext.$data.selectedPath);
$(element).on('autocomplete:selected', function(event, suggestion, dataset) {
bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : '';
});
}
};
$(element).on('autocomplete:selected', function (event, suggestion, dataset) {
bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : '';
});
}
};
}
export default {
initNoteAutocomplete,
showRecentNotes
showRecentNotes,
init
}

View File

@@ -17,6 +17,7 @@ import noteDetailRender from './note_detail_render.js';
import noteDetailRelationMap from './note_detail_relation_map.js';
import bundleService from "./bundle.js";
import attributeService from "./attributes.js";
import utils from "./utils.js";
const $noteTitle = $("#note-title");
@@ -28,6 +29,7 @@ const $noteDetailWrapper = $("#note-detail-wrapper");
const $noteIdDisplay = $("#note-id-display");
const $childrenOverview = $("#children-overview");
const $scriptArea = $("#note-detail-script-area");
const $savedIndicator = $("#saved-indicator");
let currentNote = null;
@@ -35,6 +37,8 @@ let noteChangeDisabled = false;
let isNoteChanged = false;
let detailLoadedListeners = [];
const components = {
'code': noteDetailCode,
'text': noteDetailText,
@@ -78,6 +82,8 @@ function noteChanged() {
}
isNoteChanged = true;
$savedIndicator.fadeOut();
}
async function reload() {
@@ -105,6 +111,10 @@ function onNoteChange(func) {
async function saveNote() {
const note = getCurrentNote();
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
return;
}
note.title = $noteTitle.val();
note.content = getCurrentNoteContent(note);
@@ -120,15 +130,16 @@ async function saveNote() {
protectedSessionHolder.touchProtectedSession();
}
infoService.showMessage("Saved!");
$savedIndicator.fadeIn();
}
async function saveNoteIfChanged() {
if (!isNoteChanged) {
return;
if (isNoteChanged) {
await saveNote();
}
await saveNote();
// make sure indicator is visible in a case there was some race condition.
$savedIndicator.fadeIn();
}
function setNoteBackgroundIfProtected(note) {
@@ -138,12 +149,6 @@ function setNoteBackgroundIfProtected(note) {
$unprotectButton.prop("disabled", !protectedSessionHolder.isProtectedSessionAvailable());
}
let isNewNoteCreated = false;
function newNoteCreated() {
isNewNoteCreated = true;
}
async function handleProtectedSession() {
const newSessionCreated = await protectedSessionService.ensureProtectedSession(currentNote.isProtected, false);
@@ -173,13 +178,13 @@ async function loadNoteDetail(noteId) {
// only now that we're in sync with tree active node we will switch currentNote
currentNote = loadedNote;
// needs to happend after loading the note itself because it references current noteId
attributeService.refreshAttributes();
if (isNewNoteCreated) {
isNewNoteCreated = false;
$noteTitle.focus().select();
if (utils.isDesktop()) {
// needs to happen after loading the note itself because it references current noteId
attributeService.refreshAttributes();
}
else {
// mobile usually doesn't need attributes so we just invalidate
attributeService.invalidateAttributes();
}
$noteIdDisplay.html(noteId);
@@ -193,8 +198,10 @@ async function loadNoteDetail(noteId) {
try {
$noteTitle.val(currentNote.title);
noteTypeService.setNoteType(currentNote.type);
noteTypeService.setNoteMime(currentNote.mime);
if (utils.isDesktop()) {
noteTypeService.setNoteType(currentNote.type);
noteTypeService.setNoteMime(currentNote.mime);
}
for (const componentType in components) {
if (componentType !== currentNote.type) {
@@ -210,6 +217,8 @@ async function loadNoteDetail(noteId) {
return;
}
$noteTitle.removeAttr("readonly"); // this can be set by protected session service
await getComponent(currentNote.type).show();
}
finally {
@@ -219,15 +228,19 @@ async function loadNoteDetail(noteId) {
treeService.setBranchBackgroundBasedOnProtectedStatus(noteId);
// after loading new note make sure editor is scrolled to the top
$noteDetailWrapper.scrollTop(0);
getComponent(currentNote.type).scrollToTop();
fireDetailLoaded();
$scriptArea.empty();
await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView');
await attributeService.showAttributes();
if (utils.isDesktop()) {
await attributeService.showAttributes();
await showChildrenOverview();
await showChildrenOverview();
}
}
async function showChildrenOverview() {
@@ -270,6 +283,30 @@ function focusOnTitle() {
$noteTitle.focus();
}
/**
* Since detail loading may take some time and user might just browse through the notes using UP-DOWN keys,
* we intentionally decouple activation of the note in the tree and full load of the note so just avaiting on
* fancytree's activate() won't wait for the full load.
*
* This causes an issue where in some cases you want to do some action after detail is loaded. For this reason
* we provide the listeners here which will be triggered after the detail is loaded and if the loaded note
* is the one registered in the listener.
*/
function addDetailLoadedListener(noteId, callback) {
detailLoadedListeners.push({ noteId, callback });
}
function fireDetailLoaded() {
for (const {noteId, callback} of detailLoadedListeners) {
if (noteId === currentNote.noteId) {
callback();
}
}
// all the listeners are one time only
detailLoadedListeners = [];
}
messagingService.subscribeToSyncMessages(syncData => {
if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === getCurrentNoteId())) {
infoService.showMessage('Reloading note because of background changes');
@@ -294,7 +331,7 @@ $(document).ready(() => {
// this sends the request asynchronously and doesn't wait for result
$(window).on('beforeunload', () => { saveNoteIfChanged(); }); // don't convert to short form, handler doesn't like returned promise
setInterval(saveNoteIfChanged, 5000);
setInterval(saveNoteIfChanged, 3000);
export default {
reload,
@@ -304,11 +341,11 @@ export default {
getCurrentNote,
getCurrentNoteType,
getCurrentNoteId,
newNoteCreated,
focusOnTitle,
saveNote,
saveNoteIfChanged,
noteChanged,
getCurrentNoteContent,
onNoteChange
onNoteChange,
addDetailLoadedListener
};

View File

@@ -3,6 +3,7 @@ import bundleService from "./bundle.js";
import infoService from "./info.js";
import server from "./server.js";
import noteDetailService from "./note_detail.js";
import utils from "./utils.js";
let codeEditor = null;
@@ -32,7 +33,10 @@ async function show() {
lint: true,
gutters: ["CodeMirror-lint-markers"],
lineNumbers: true,
tabindex: 100
tabindex: 100,
// we linewrap partly also because without it horizontal scrollbar displays only when you scroll
// all the way to the bottom of the note. With line wrap there's no horizontal scrollbar so no problem
lineWrapping: true
});
onNoteChange(noteDetailService.noteChanged);
@@ -43,7 +47,9 @@ async function show() {
const currentNote = noteDetailService.getCurrentNote();
// this needs to happen after the element is shown, otherwise the editor won't be refreshed
codeEditor.setValue(currentNote.content);
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
// we provide fallback
codeEditor.setValue(currentNote.content || "");
const info = CodeMirror.findModeByMIME(currentNote.mime);
@@ -89,7 +95,7 @@ function onNoteChange(func) {
codeEditor.on('change', func);
}
$(document).bind('keydown', "ctrl+return", executeCurrentNote);
utils.bindShortcut("ctrl+return", executeCurrentNote);
$executeScriptButton.click(executeCurrentNote);
@@ -102,5 +108,6 @@ export default {
if (codeEditor) {
codeEditor.setValue('');
}
}
},
scrollToTop: () => $component.scrollTop(0)
}

View File

@@ -53,5 +53,6 @@ export default {
getContent: () => null,
focus: () => null,
onNoteChange: () => null,
cleanup: () => null
cleanup: () => null,
scrollToTop: () => null
}

View File

@@ -5,6 +5,7 @@ import infoService from "./info.js";
import server from "./server.js";
const $component = $('#note-detail-image');
const $imageWrapper = $('#note-detail-image-wrapper');
const $imageView = $('#note-detail-image-view');
const $imageDownloadButton = $("#image-download");
@@ -39,10 +40,10 @@ function selectImage(element) {
}
$copyToClipboardButton.click(() => {
$component.attr('contenteditable','true');
$imageWrapper.attr('contenteditable','true');
try {
selectImage($component.get(0));
selectImage($imageWrapper.get(0));
const success = document.execCommand('copy');
@@ -55,7 +56,7 @@ $copyToClipboardButton.click(() => {
}
finally {
window.getSelection().removeAllRanges();
$component.removeAttr('contenteditable');
$imageWrapper.removeAttr('contenteditable');
}
});
@@ -70,5 +71,6 @@ export default {
getContent: () => null,
focus: () => null,
onNoteChange: () => null,
cleanup: () => null
cleanup: () => null,
scrollToTop: () => $component.scrollTop(0)
}

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