feat(docs): revamp "button use case"

This commit is contained in:
Elian Doran 2025-04-04 23:46:07 +03:00
parent 65e914f916
commit bb23ae6813
No known key found for this signature in database
9 changed files with 409 additions and 72 deletions

View File

@ -4641,13 +4641,6 @@
"type": "text", "type": "text",
"mime": "text/markdown", "mime": "text/markdown",
"attributes": [ "attributes": [
{
"type": "relation",
"name": "imageLink",
"value": "DVJl4l3T8EG2",
"isInheritable": false,
"position": 10
},
{ {
"type": "relation", "type": "relation",
"name": "internalLink", "name": "internalLink",
@ -4662,13 +4655,6 @@
"isInheritable": false, "isInheritable": false,
"position": 30 "position": 30
}, },
{
"type": "relation",
"name": "internalLink",
"value": "wX4HbRucYSDD",
"isInheritable": false,
"position": 40
},
{ {
"type": "relation", "type": "relation",
"name": "internalLink", "name": "internalLink",
@ -4703,11 +4689,108 @@
"value": "scripts", "value": "scripts",
"isInheritable": false, "isInheritable": false,
"position": 20 "position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "TjLYAo3JMO8X",
"isInheritable": false,
"position": 90
} }
], ],
"format": "markdown", "format": "markdown",
"dataFileName": "Scripts.md", "dataFileName": "Scripts.md",
"attachments": [] "attachments": [],
"dirFileName": "Scripts",
"children": [
{
"isClone": false,
"noteId": "TjLYAo3JMO8X",
"notePath": [
"pOsGYCXsbNQG",
"KSZ04uQ2D1St",
"6f9hih2hXXZk",
"CdNpE2pqjmI6",
"TjLYAo3JMO8X"
],
"title": "\"New Task\" launcher button",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "internalLink",
"value": "xYjQUYhpbUEW",
"isInheritable": false,
"position": 10
},
{
"type": "relation",
"name": "internalLink",
"value": "xYmIYSP6wE3F",
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "6f9hih2hXXZk",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "yIhgI5H7A2Sm",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "m1lbrzyKDaRB",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "s8alTXmpFR61",
"isInheritable": false,
"position": 70
},
{
"type": "label",
"name": "iconClass",
"value": "bx bx-task",
"isInheritable": false,
"position": 80
}
],
"format": "markdown",
"dataFileName": "New Task launcher button.md",
"attachments": [
{
"attachmentId": "9C2JA6tdtRpN",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "New Task launcher button_i.png"
}
]
}
]
}, },
{ {
"isClone": false, "isClone": false,

View File

@ -10,28 +10,15 @@ To go further I must explain basic architecture of Trilium - in its essence it i
So we have frontend and backend, each with their own set of responsibilities, but their common feature is that they both run JavaScript code. Add to this the fact, that we're able to create JavaScript \[\[code notes\]\] and we're onto something. So we have frontend and backend, each with their own set of responsibilities, but their common feature is that they both run JavaScript code. Add to this the fact, that we're able to create JavaScript \[\[code notes\]\] and we're onto something.
## Button use case ## Use cases
Let's take a look at our demo script (shipped with default Trilium [database](../../Advanced%20Usage/Database.md)) - Task manager. One of the things this script does is adding a button to the Trilium interface which will allow user to easily add new Task (TODO item). * [A button launcher button](Scripts/New%20Task%20launcher%20button.md)
![](../../Attachments/button-script.png) ## Action handler
First take a look at the red circle all the way on the top - this what we want to achieve - new button in UI which will create new note representing a task/todo item.
Red point below the first one marks the note type we have created for this script - it's "JavaScript frontend". It's frontend because adding button to UI is clearly frontend responsibility.
In the note content you can see the code which calls one of the API methods, this one is specifically meant to add new buttons. Code needs to set few button properties:
* button title
* icon which should appear on the button
* optional shortcut under which you can trigger the button
* most importantly "action" - what must happen when button is clicked
### Action handler
Saving the note to the database is backend's responsibility, so we immediately pass control to the backend and ask it to create a note. Once this is done, we show the newly created note so that the user can set the task title and maybe some attributes. Saving the note to the database is backend's responsibility, so we immediately pass control to the backend and ask it to create a note. Once this is done, we show the newly created note so that the user can set the task title and maybe some attributes.
### Script execution ## Script execution
So we have a script which will add the button to the toolbar. But how can we execute it? One possibility is to click on "play" icon (marked by red circle). The problem with this is that this UI change is time bound by Trilium runtime so when we restart Trilium, button won't be there. So we have a script which will add the button to the toolbar. But how can we execute it? One possibility is to click on "play" icon (marked by red circle). The problem with this is that this UI change is time bound by Trilium runtime so when we restart Trilium, button won't be there.
@ -41,7 +28,7 @@ The solution is marked by red circle at the bottom - this note has [label](../..
(`#run=frontendStartup` does not work for [Mobile frontend](../../Installation%20%26%20Setup/Mobile%20Frontend.md) - if you want to have scripts running there, give the script `#run=mobileStartup` label) (`#run=frontendStartup` does not work for [Mobile frontend](../../Installation%20%26%20Setup/Mobile%20Frontend.md) - if you want to have scripts running there, give the script `#run=mobileStartup` label)
### More showcases ## More showcases
You can see more scripting with explanation in [Advanced showcases](../../Advanced%20Usage/Advanced%20Showcases.md) You can see more scripting with explanation in [Advanced showcases](../../Advanced%20Usage/Advanced%20Showcases.md)

View File

@ -0,0 +1,47 @@
# "New Task" launcher button
In this example we are going to extend the functionality of the [Task Manager](../../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.md) showcase (which comes by default with Trilium) by adding a button in the [Launch Bar](../../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.md)  (![](New%20Task%20launcher%20button_i.png)) to create a new task automatically and open it.
## Creating the note
1. First, create a new [Code](../../Code.md) note type with the _JS frontend_ language.
2. Define the `#run=frontendStartup` label in [Attributes](../../../Advanced%20Usage/Attributes.md).
## 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 style="width:53.57%;"><col style="width:46.43%;"></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="../../../Developer%20Guides/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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

View File

@ -4641,13 +4641,6 @@
"type": "text", "type": "text",
"mime": "text/markdown", "mime": "text/markdown",
"attributes": [ "attributes": [
{
"type": "relation",
"name": "imageLink",
"value": "DVJl4l3T8EG2",
"isInheritable": false,
"position": 10
},
{ {
"type": "relation", "type": "relation",
"name": "internalLink", "name": "internalLink",
@ -4662,13 +4655,6 @@
"isInheritable": false, "isInheritable": false,
"position": 30 "position": 30
}, },
{
"type": "relation",
"name": "internalLink",
"value": "wX4HbRucYSDD",
"isInheritable": false,
"position": 40
},
{ {
"type": "relation", "type": "relation",
"name": "internalLink", "name": "internalLink",
@ -4703,11 +4689,108 @@
"value": "scripts", "value": "scripts",
"isInheritable": false, "isInheritable": false,
"position": 20 "position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "TjLYAo3JMO8X",
"isInheritable": false,
"position": 90
} }
], ],
"format": "html", "format": "html",
"dataFileName": "Scripts.html", "dataFileName": "Scripts.html",
"attachments": [] "attachments": [],
"dirFileName": "Scripts",
"children": [
{
"isClone": false,
"noteId": "TjLYAo3JMO8X",
"notePath": [
"pOsGYCXsbNQG",
"KSZ04uQ2D1St",
"6f9hih2hXXZk",
"CdNpE2pqjmI6",
"TjLYAo3JMO8X"
],
"title": "\"New Task\" launcher button",
"notePosition": 20,
"prefix": null,
"isExpanded": false,
"type": "text",
"mime": "text/html",
"attributes": [
{
"type": "relation",
"name": "internalLink",
"value": "xYjQUYhpbUEW",
"isInheritable": false,
"position": 10
},
{
"type": "relation",
"name": "internalLink",
"value": "xYmIYSP6wE3F",
"isInheritable": false,
"position": 20
},
{
"type": "relation",
"name": "internalLink",
"value": "6f9hih2hXXZk",
"isInheritable": false,
"position": 30
},
{
"type": "relation",
"name": "internalLink",
"value": "zEY4DaJG4YT5",
"isInheritable": false,
"position": 40
},
{
"type": "relation",
"name": "internalLink",
"value": "yIhgI5H7A2Sm",
"isInheritable": false,
"position": 50
},
{
"type": "relation",
"name": "internalLink",
"value": "m1lbrzyKDaRB",
"isInheritable": false,
"position": 60
},
{
"type": "relation",
"name": "internalLink",
"value": "s8alTXmpFR61",
"isInheritable": false,
"position": 70
},
{
"type": "label",
"name": "iconClass",
"value": "bx bx-task",
"isInheritable": false,
"position": 80
}
],
"format": "html",
"dataFileName": "New Task launcher button.html",
"attachments": [
{
"attachmentId": "9C2JA6tdtRpN",
"title": "image.png",
"role": "image",
"mime": "image/png",
"position": 10,
"dataFileName": "New Task launcher button_i.png"
}
]
}
]
}, },
{ {
"isClone": false, "isClone": false,

View File

@ -31,35 +31,17 @@
but their common feature is that they both run JavaScript code. Add to but their common feature is that they both run JavaScript code. Add to
this the fact, that we're able to create JavaScript [[code notes]] and this the fact, that we're able to create JavaScript [[code notes]] and
we're onto something.</p> we're onto something.</p>
<h2>Button use case</h2> <h2>Use cases</h2>
<p>Let's take a look at our demo script (shipped with default Trilium <a href="../../Advanced%20Usage/Database.html">database</a>)
- Task manager. One of the things this script does is adding a button to
the Trilium interface which will allow user to easily add new Task (TODO
item).</p>
<p>
<img src="../../Attachments/button-script.png">
</p>
<p>First take a look at the red circle all the way on the top - this what
we want to achieve - new button in UI which will create new note representing
a task/todo item.</p>
<p>Red point below the first one marks the note type we have created for
this script - it's "JavaScript frontend". It's frontend because adding
button to UI is clearly frontend responsibility.</p>
<p>In the note content you can see the code which calls one of the API methods,
this one is specifically meant to add new buttons. Code needs to set few
button properties:</p>
<ul> <ul>
<li>button title</li> <li><a class="reference-link" href="Scripts/New%20Task%20launcher%20button.html">A button launcher button</a>
<li>icon which should appear on the button</li> </li>
<li>optional shortcut under which you can trigger the button</li>
<li>most importantly "action" - what must happen when button is clicked</li>
</ul> </ul>
<h3>Action handler</h3> <h2>Action handler</h2>
<p>Saving the note to the database is backend's responsibility, so we immediately <p>Saving the note to the database is backend's responsibility, so we immediately
pass control to the backend and ask it to create a note. Once this is done, pass control to the backend and ask it to create a note. Once this is done,
we show the newly created note so that the user can set the task title we show the newly created note so that the user can set the task title
and maybe some attributes.</p> and maybe some attributes.</p>
<h3>Script execution</h3> <h2>Script execution</h2>
<p>So we have a script which will add the button to the toolbar. But how <p>So we have a script which will add the button to the toolbar. But how
can we execute it? One possibility is to click on "play" icon (marked by can we execute it? One possibility is to click on "play" icon (marked by
red circle). The problem with this is that this UI change is time bound red circle). The problem with this is that this UI change is time bound
@ -72,7 +54,7 @@
Trilium frontend starts up.</p> Trilium frontend starts up.</p>
<p>(<code>#run=frontendStartup</code> does not work for <a href="../../Installation%20%26%20Setup/Mobile%20Frontend.html">Mobile frontend</a> - <p>(<code>#run=frontendStartup</code> does not work for <a href="../../Installation%20%26%20Setup/Mobile%20Frontend.html">Mobile frontend</a> -
if you want to have scripts running there, give the script <code>#run=mobileStartup</code> label)</p> if you want to have scripts running there, give the script <code>#run=mobileStartup</code> label)</p>
<h3>More showcases</h3> <h2>More showcases</h2>
<p>You can see more scripting with explanation in <a href="../../Advanced%20Usage/Advanced%20Showcases.html">Advanced showcases</a> <p>You can see more scripting with explanation in <a href="../../Advanced%20Usage/Advanced%20Showcases.html">Advanced showcases</a>
</p> </p>
<h2>Events</h2> <h2>Events</h2>

View File

@ -0,0 +1,150 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../../../style.css">
<base target="_parent">
<title data-trilium-title>&quot;New Task&quot; launcher button</title>
</head>
<body>
<div class="content">
<h1 data-trilium-h1>&quot;New Task&quot; launcher button</h1>
<div class="ck-content">
<p>In this example we are going to extend the functionality of the&nbsp;
<a
class="reference-link" href="../../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.html">Task Manager</a>&nbsp;showcase (which comes by default with Trilium) by
adding a button in the&nbsp;<a class="reference-link" href="../../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.html">Launch Bar</a>&nbsp;
(
<img src="New Task launcher button_i.png" width="19" height="21">) to create a new task automatically and open it.</p>
<h2>Creating the note</h2>
<ol>
<li>First, create a new&nbsp;<a class="reference-link" href="../../Code.html">Code</a>&nbsp;note
type with the <em>JS frontend</em> language.</li>
<li>Define the <code>#run=frontendStartup</code> label in&nbsp;<a class="reference-link"
href="../../../Advanced%20Usage/Attributes.html">Attributes</a>.</li>
</ol>
<h2>Content of the script</h2>
<p>Copy-paste the following script:</p><pre><code class="language-application-javascript-env-frontend">api.addButtonToToolbar({
title: "New task",
icon: "task",
shortcut: "alt+n",
action: async () =&gt; {
const taskNoteId = await api.runOnBackend(() =&gt; {
const todoRootNote = api.getNoteWithLabel("taskTodoRoot");
const resp = api.createTextNote(todoRootNote.noteId, "New task", "")
return resp.note.noteId;
});
await api.waitUntilSynced();
await api.activateNewNote(taskNoteId);
}
});</code></pre>
<h2>Testing the functionality</h2>
<p>Since we set the script to be run on start-up, all we need to do is to
<a
href="../../../Troubleshooting/Refreshing%20the%20application.html">refresh the application</a>.</p>
<h2>Understanding how the script works</h2>
<figure class="table" style="width:96.48%;">
<table class="ck-table-resized">
<colgroup>
<col style="width:53.57%;">
<col style="width:46.43%;">
</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="../../../Developer%20Guides/Frontend%20Basics.html">Front-end API</a> to
create a icon in the&nbsp;<a class="reference-link" href="../../../Basic%20Concepts%20and%20Features/UI%20Elements/Launch%20Bar.html">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.html">label</a> <code>#taskTodoRoot</code>.
This is how the&nbsp;<a class="reference-link" href="../../../Advanced%20Usage/Advanced%20Showcases/Task%20Manager.html">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.html">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>
</figure>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

View File

@ -240,6 +240,11 @@
<li><a href="User%20Guide/Note%20Types/Code.html" target="detail">Code</a> <li><a href="User%20Guide/Note%20Types/Code.html" target="detail">Code</a>
<ul> <ul>
<li><a href="User%20Guide/Note%20Types/Code/Scripts.html" target="detail">Scripts</a> <li><a href="User%20Guide/Note%20Types/Code/Scripts.html" target="detail">Scripts</a>
<ul>
<li><a href="User%20Guide/Note%20Types/Code/Scripts/New%20Task%20launcher%20button.html"
target="detail">&quot;New Task&quot; launcher button</a>
</li>
</ul>
</li> </li>
<li><a href="User%20Guide/Note%20Types/Code/Script%20API.html" target="detail">Script API</a> <li><a href="User%20Guide/Note%20Types/Code/Script%20API.html" target="detail">Script API</a>
</li> </li>