docs(dev): reorganize and clean up technical documentation

This commit is contained in:
Elian Doran
2025-11-04 10:55:48 +02:00
parent db644f20ed
commit 0ae4defc6d
71 changed files with 1144 additions and 1757 deletions

View File

@@ -1,15 +1,15 @@
# Events
[Script](../Scripting.md) notes can be triggered by events. Note that these are backend events and thus relation need to point to the "JS backend" code note.
[Script](../../Scripting.md) notes can be triggered by events. Note that these are backend events and thus relation need to point to the "JS backend" code note.
## Global events
Global events are attached to the script note via label. Simply create e.g. "run" label with some of these values and script note will be executed once the event occurs.
<table><thead><tr><th>Label</th><th>Description</th></tr></thead><tbody><tr><td><code>run</code></td><td><p>Defines on which events script should run. Possible values are:</p><ul><li><code>frontendStartup</code> - when Trilium frontend starts up (or is refreshed), but not on mobile.</li><li><code>mobileStartup</code> - when Trilium frontend starts up (or is refreshed), on mobile.</li><li><code>backendStartup</code> - when Trilium backend starts up</li><li><code>hourly</code> - run once an hour. You can use additional label <code>runAtHour</code> to specify at which hour, on the back-end.</li><li><code>daily</code> - run once a day, on the back-end</li></ul></td></tr><tr><td><code>runOnInstance</code></td><td>Specifies that the script should only run on a particular&nbsp;<a class="reference-link" href="../Advanced%20Usage/Configuration%20(config.ini%20or%20environment%20variables)/Trilium%20instance.md">Trilium instance</a>.</td></tr><tr><td><code>runAtHour</code></td><td>On which hour should this run. Should be used together with <code>#run=hourly</code>. Can be defined multiple times for more runs during the day.</td></tr></tbody></table>
<table><thead><tr><th>Label</th><th>Description</th></tr></thead><tbody><tr><td><code>run</code></td><td><p>Defines on which events script should run. Possible values are:</p><ul><li><code>frontendStartup</code> - when Trilium frontend starts up (or is refreshed), but not on mobile.</li><li><code>mobileStartup</code> - when Trilium frontend starts up (or is refreshed), on mobile.</li><li><code>backendStartup</code> - when Trilium backend starts up</li><li><code>hourly</code> - run once an hour. You can use additional label <code>runAtHour</code> to specify at which hour, on the back-end.</li><li><code>daily</code> - run once a day, on the back-end</li></ul></td></tr><tr><td><code>runOnInstance</code></td><td>Specifies that the script should only run on a particular&nbsp;<a class="reference-link" href="../../Advanced%20Usage/Configuration%20(config.ini%20or%20environment%20variables)/Trilium%20instance.md">Trilium instance</a>.</td></tr><tr><td><code>runAtHour</code></td><td>On which hour should this run. Should be used together with <code>#run=hourly</code>. Can be defined multiple times for more runs during the day.</td></tr></tbody></table>
## Entity events
Other events are bound to some entity, these are defined as [relations](../Advanced%20Usage/Attributes.md) - meaning that script is triggered only if note has this script attached to it through relations (or it can inherit it).
Other events are bound to some entity, these are defined as [relations](../../Advanced%20Usage/Attributes.md) - meaning that script is triggered only if note has this script attached to it through relations (or it can inherit it).
| Relation | Description |
| --- | --- |

View File

@@ -0,0 +1,11 @@
# Server-side imports
Older versions of Trilium Notes allowed the use of Common.js module imports inside backend scripts, such as:
```
const isBetween = require('dayjs/plugin/isBetween')
api.dayjs.extend(isBetween)
```
For newer versions, Node.js imports are **not officially supported anymore**, since we've added a bundler which makes it more difficult to reuse dependencies.
Theoretically it's still possible to use imports by manually setting up a `node_modules` in the server directory via `npm` or `pnpm`.

View File

@@ -1,47 +0,0 @@
# "New Task" launcher button
In this example we are going to extend the functionality of <a class="reference-link" href="../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.md">Task Manager</a> showcase (which comes by default with Trilium) by adding a button in the <a class="reference-link" href="../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.md">Launch Bar</a>  (![](New%20Task%20launcher%20button_i.png)) to create a new task automatically and open it.
## Creating the note
1. First, create a new <a class="reference-link" href="../../Note%20Types/Code.md">Code</a> note type with the _JS frontend_ language.
2. Define the `#run=frontendStartup` label in <a class="reference-link" href="../../Advanced%20Usage/Attributes.md">Attributes</a>.
## Content of the script
Copy-paste the following script:
```javascript
api.addButtonToToolbar({
title: "New task",
icon: "task",
shortcut: "alt+n",
action: async () => {
const taskNoteId = await api.runOnBackend(() => {
const todoRootNote = api.getNoteWithLabel("taskTodoRoot");
const resp = api.createTextNote(todoRootNote.noteId, "New task", "")
return resp.note.noteId;
});
await api.waitUntilSynced();
await api.activateNewNote(taskNoteId);
}
});
```
## Testing the functionality
Since we set the script to be run on start-up, all we need to do is to [refresh the application](../../Troubleshooting/Refreshing%20the%20application.md).
## Understanding how the script works
<table class="ck-table-resized"><colgroup><col><col></colgroup><tbody><tr><td><pre><code class="language-application-javascript-env-frontend">api.addButtonToToolbar({
title: "New task",
icon: "task",
shortcut: "alt+n",
action: async () =&gt; {
// [...]
}
});</code></pre></td><td><p>This uses the <a href="../Frontend%20Basics.md">Front-end API</a> to create a icon in the&nbsp;<a class="reference-link" href="../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.md">Launch Bar</a>, by specifying:</p><ul><li>A title</li><li>A corresponding boxicons icon (without the <code>bx-</code> prefix).</li><li>Optionally, a keyboard shortcut to assign to it.</li><li>The action, which will be executed when the button is pressed.</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const taskNoteId = await api.runOnBackend(() =&gt; {
// Shown below.
return resp.note.noteId;
});</code></pre></td><td><ul><li>This portion of code is actually executed on the server (backend) and not on the client (i.e. browser).<ul><li>The reason is that the creating notes is the responsibility of the server.</li></ul></li><li>Here we can also see that it is possible to return results from the server execution and read them in the client (<code>taskNoteId</code>).</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const todoRootNote = api.getNoteWithLabel("taskTodoRoot");</code></pre></td><td><ul><li>Here we identify a note with the <a href="../../Advanced%20Usage/Attributes.md">label</a> <code>#taskTodoRoot</code>. This is how the&nbsp;<a class="reference-link" href="../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.md">Task Manager</a>&nbsp;showcase knows where to place all the different tasks.</li><li>Normally this might return a <code>null</code> value if no such note could be identified, but error handling is outside the scope of this example.&nbsp;</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const resp = api.createTextNote(todoRootNote.noteId, "New task", "")</code></pre></td><td><ul><li>We create a new child note within the to-do root note (first argument) with the title “New task" (second argument) and no content by default (third argument).</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">await api.waitUntilSynced();</code></pre></td><td><ul><li>Back on the client, since we created a new note on the server, we now need to wait for the change to be reflected in the client.</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">await api.activateNewNote(taskNoteId);</code></pre></td><td><ul><li>Since we know the <a href="../../Advanced%20Usage/Note%20ID.md">ID</a> of the newly created note, all we have to do now is to show this note to the user.</li></ul></td></tr></tbody></table>

View File

@@ -54,4 +54,4 @@ Conversely to scripts, widgets do have some specific requirements in order to wo
### Tutorial
For more information on building widgets, take a look at [Widget Basics](Custom%20Widgets/Widget%20Basics.md).
For more information on building widgets, take a look at [Widget Basics](Frontend%20Basics/Custom%20Widgets/Widget%20Basics.md).

View File

@@ -0,0 +1,15 @@
# CSS
In `doRender()`:
```
this.cssBlock(`#my-widget {
position: absolute;
bottom: 40px;
left: 60px;
z-index: 1;
}`)
```
* * *
Reference: [https://trilium.rocks/X7pxYpiu0lgU](https://trilium.rocks/X7pxYpiu0lgU)

View File

@@ -0,0 +1,32 @@
# Right pane widget
* `doRender` must not be overridden, instead `doRenderBody()` has to be overridden.
* `parentWidget()` must be set to `“rightPane”`.
* `widgetTitle()` getter can optionally be overriden, otherwise the widget will be displayed as “Untitled widget”.
```
const template = `<div>Hi</div>`;
class ToDoListWidget extends api.RightPanelWidget {
get widgetTitle() {
return "Title goes here";
}
get parentWidget() { return "right-pane" }
doRenderBody() {
this.$body.empty().append($(template));
}
async refreshWithNote(note) {
this.toggleInt(false);
this.triggerCommand("reEvaluateRightPaneVisibility");
this.toggleInt(true);
this.triggerCommand("reEvaluateRightPaneVisibility");
}
}
module.exports = new ToDoListWidget();
```
The implementation is in `src/public/app/widgets/right_panel_widget.js`.

View File

@@ -22,10 +22,10 @@ module.exports = new MyWidget();
To implement this widget:
1. Create a new `JS Frontend` note in Trilium and paste in the code above.
2. Assign the `#widget` [attribute](../../Advanced%20Usage/Attributes.md) to the [note](../../Basic%20Concepts%20and%20Features/Notes.md).
2. Assign the `#widget` [attribute](../../../Advanced%20Usage/Attributes.md) to the [note](../../../Basic%20Concepts%20and%20Features/Notes.md).
3. Restart Trilium or reload the window.
To verify that the widget is working, open the developer tools (`Cmd` + `Shift` + `I`) and run `document.querySelector("#my-widget")`. If the element is found, the widget is functioning correctly. If `undefined` is returned, double-check that the [note](../../Basic%20Concepts%20and%20Features/Notes.md) has the `#widget` [attribute](../../Advanced%20Usage/Attributes.md).
To verify that the widget is working, open the developer tools (`Cmd` + `Shift` + `I`) and run `document.querySelector("#my-widget")`. If the element is found, the widget is functioning correctly. If `undefined` is returned, double-check that the [note](../../../Basic%20Concepts%20and%20Features/Notes.md) has the `#widget` [attribute](../../../Advanced%20Usage/Attributes.md).
### Step 2: Adding an UI Element
@@ -85,7 +85,7 @@ After reloading Trilium, the button should now appear at the bottom left of the
### Step 4: Adding User Interaction
Lets make the button interactive by showing a message when its clicked. We'll use the `api.showMessage` method from the [Script API](../Script%20API.md).
Lets make the button interactive by showing a message when its clicked. We'll use the `api.showMessage` method from the [Script API](../../Script%20API.md).
```
class MyWidget extends api.BasicWidget {
@@ -108,4 +108,11 @@ class MyWidget extends api.BasicWidget {
module.exports = new MyWidget();
```
Reload the application one last time. When you click the button, a "Hello World!" message should appear, confirming that your widget is fully functional.
`parentWidget()` can be given the following values:
* `left-pane` - This renders the widget on the left side of the screen where the note tree lives.
* `center-pane` - This renders the widget in the center of the layout in the same location that notes and splits appear.
* `note-detail-pane` - This renders the widget _with_ the note in the center pane. This means it can appear multiple times with splits.
* `right-pane` - This renders the widget to the right of any opened notes.
[Reload](../../../Troubleshooting/Refreshing%20the%20application.md) the application one last time. When you click the button, a "Hello World!" message should appear, confirming that your widget is fully functional.

View File

@@ -1,8 +1,8 @@
# Word count widget
> [!TIP]
> This widget is also present in new installations in the <a class="reference-link" href="../../Advanced%20Usage/Database/Demo%20Notes.md">Demo Notes</a>.
> This widget is also present in new installations in the <a class="reference-link" href="../../../Advanced%20Usage/Database/Demo%20Notes.md">Demo Notes</a>.
Create a <a class="reference-link" href="../../Note%20Types/Code.md">Code</a> note of type JS frontend and **give it a** `#widget` **label**.
Create a <a class="reference-link" href="../../../Note%20Types/Code.md">Code</a> note of type JS frontend and **give it a** `#widget` **label**.
```
/*
@@ -82,7 +82,7 @@ class WordCountWidget extends api.NoteContextAwareWidget {
module.exports = new WordCountWidget();
```
After you make changes it is necessary to [restart Trilium](../../Troubleshooting/Refreshing%20the%20application.md) so that the layout can be rebuilt.
After you make changes it is necessary to [restart Trilium](../../../Troubleshooting/Refreshing%20the%20application.md) so that the layout can be rebuilt.
At the bottom of the note you can see the resulting widget:

View File

@@ -0,0 +1,47 @@
# "New Task" launcher button
In this example we are going to extend the functionality of <a class="reference-link" href="../../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.md">Task Manager</a> showcase (which comes by default with Trilium) by adding a button in the <a class="reference-link" href="../../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.md">Launch Bar</a>  (![](New%20Task%20launcher%20button_i.png)) to create a new task automatically and open it.
## Creating the note
1. First, create a new <a class="reference-link" href="../../../Note%20Types/Code.md">Code</a> note type with the _JS frontend_ language.
2. Define the `#run=frontendStartup` label in <a class="reference-link" href="../../../Advanced%20Usage/Attributes.md">Attributes</a>.
## Content of the script
Copy-paste the following script:
```javascript
api.addButtonToToolbar({
title: "New task",
icon: "task",
shortcut: "alt+n",
action: async () => {
const taskNoteId = await api.runOnBackend(() => {
const todoRootNote = api.getNoteWithLabel("taskTodoRoot");
const resp = api.createTextNote(todoRootNote.noteId, "New task", "")
return resp.note.noteId;
});
await api.waitUntilSynced();
await api.activateNewNote(taskNoteId);
}
});
```
## Testing the functionality
Since we set the script to be run on start-up, all we need to do is to [refresh the application](../../../Troubleshooting/Refreshing%20the%20application.md).
## Understanding how the script works
<table class="ck-table-resized"><colgroup><col><col></colgroup><tbody><tr><td><pre><code class="language-application-javascript-env-frontend">api.addButtonToToolbar({
title: "New task",
icon: "task",
shortcut: "alt+n",
action: async () =&gt; {
// [...]
}
});</code></pre></td><td><p>This uses the <a href="../../Frontend%20Basics.md">Front-end API</a> to create a icon in the&nbsp;<a class="reference-link" href="../../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.md">Launch Bar</a>, by specifying:</p><ul><li>A title</li><li>A corresponding boxicons icon (without the <code>bx-</code> prefix).</li><li>Optionally, a keyboard shortcut to assign to it.</li><li>The action, which will be executed when the button is pressed.</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const taskNoteId = await api.runOnBackend(() =&gt; {
// Shown below.
return resp.note.noteId;
});</code></pre></td><td><ul><li>This portion of code is actually executed on the server (backend) and not on the client (i.e. browser).<ul><li>The reason is that the creating notes is the responsibility of the server.</li></ul></li><li>Here we can also see that it is possible to return results from the server execution and read them in the client (<code>taskNoteId</code>).</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const todoRootNote = api.getNoteWithLabel("taskTodoRoot");</code></pre></td><td><ul><li>Here we identify a note with the <a href="../../../Advanced%20Usage/Attributes.md">label</a> <code>#taskTodoRoot</code>. This is how the&nbsp;<a class="reference-link" href="../../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.md">Task Manager</a>&nbsp;showcase knows where to place all the different tasks.</li><li>Normally this might return a <code>null</code> value if no such note could be identified, but error handling is outside the scope of this example.&nbsp;</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">const resp = api.createTextNote(todoRootNote.noteId, "New task", "")</code></pre></td><td><ul><li>We create a new child note within the to-do root note (first argument) with the title “New task" (second argument) and no content by default (third argument).</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">await api.waitUntilSynced();</code></pre></td><td><ul><li>Back on the client, since we created a new note on the server, we now need to wait for the change to be reflected in the client.</li></ul></td></tr><tr><td><pre><code class="language-application-javascript-env-frontend">await api.activateNewNote(taskNoteId);</code></pre></td><td><ul><li>Since we know the <a href="../../../Advanced%20Usage/Note%20ID.md">ID</a> of the newly created note, all we have to do now is to show this note to the user.</li></ul></td></tr></tbody></table>