TiddlyWiki is a very good thing and I've been using it for a long time. However, some things are not in it, and this is a minus. But it can be creatively finished with a file, and this is a plus.
I needed a progress bar. He has a lot of applications for him: show the readiness of the post, for example. Or the number of completed cases compared with the remaining. Anyway, visual thing.
Since there is no progress bar out of the box, I began to think about how to add it. And, for starters, formulated the requirements for it. The progress bar should be able to set the following parameters:
')
- fill color;
- the size;
- help when you hover.
If a parameter is not specified, it should be calculated automatically.
There are
macros for solving such problems in TiddlyWiki
. This is a predefined piece of text, where you can pass the parameters and substitute them in the right places.
As part of the experiment, I sketched a test macro that displays the progress bar:
\define progressbar(count:"0" total:"10") <svg width="$total$5" height="15"> <g> <title>$count$ $total$</title> <rect x="1.5" y="4.5" height="10" width="$count$0" rx="3" ry="3" style="fill: green; stroke: none" /> <rect x="1.5" y="4.5" height="10" width="$total$0" rx="3" ry="3" style="fill: none; stroke: green" /> </g> </svg> \end
In the same
tiddler (as in TiddlyWiki is called a fragment of the text) added at the bottom of the call to this macro:
: <<progressbar 3 4>>
Saved the tiddler and admired the result:

The scheme was fundamentally working. But she had a lot of inconsistencies with the original requirements. And it was not yet possible to fix it because of the extremely limited creation of macros using the WikiText format. I had to understand further.
The documentation found mention that macros can be written in JavaScript. To do this, a macro tiddler must contain a
module-type
field with a
macro
value (the fields in TiddlyWiki are metadata and can be assigned to any tiddler). The macro script must export the following properties:
name
: A string representing the name by which the macro will be called.params
: An array of objects with the following properties:
name
: parameter namedefault
: (optional) default parameter value
run
: The function that will be called when the macro is run. Parameters are retrieved from the macro call and arranged according to the params array. The run
function should return the string value of the macro. When called, this
points to the node of the widget that called the macro.
If the
params
array is empty or missing, all parameters will be simply passed to the
run()
method.
It was already good. But in TiddlyWiki, you can't just take and make a tiddler with a piece of JavaScript. Rather, you can, but will not work. For the construction to work, it must be properly formatted. For example, make a
plugin.What is a plugin in TiddlyWiki terminology? This is a set of tiddler, assembled into a single unit, which is marked as hidden and not displayed in the usual list of tiddler, can be embedded in the system and run for execution, and can also be imported from one wiki to another couple of clicks.
Initially, writing plug-ins required deploying a rather complex infrastructure using
node.js. I once tried to do it, but it did not work out (I don’t remember for what reason). However, at the moment the developer has added the ability to write plugins directly in the browser, which I used and will now tell you how to do it.
So, dear readers, let's get down to creating a plugin. Checking the
documentation , download the clean TiddlyWiki file and start making a plugin from it.
The first thing to do is to create HelloThere
tiddler , configure it to automatically display when you open the page and register in it links to the plugin tiddler.
The path to the plugin, according to the documentation, should look like this:
$:/plugins/_/_
The path to the scripts included in the plugin is configured in the same way:
$:/plugins/_/_/_.js
This is my version of HelloThere
tiddler :
* [[$:/plugins/morthan/progress]] * [[$:/plugins/morthan/progress/progressbar.js]] : ; `count` : ; `total` : ; `width` :
And this is it in the rendered form:

It is worth paying attention to two things. First, the links are given in italics, because neither the plug-in nor the script included in its composition, yet exists. Secondly, the progress bar is also not drawn yet - for the same reason.
To set up an automatic tiddler display when a page opens, add it to the
Default tiddlers list. It can be found either in the GettingStarted
tiddler that opens by default, or you can find the gear icon in the sidebar and click it. In the settings panel that appears, look for
Default tiddlers and write our
HelloThere there .

Everything, the first part is ready. Now you need to create the plugin and script tiddler. Let's start with the plugin.
To create a tiddler, just click on the link to it. A blank tiddler appears, click "Edit" and edit.
As the documentation suggests, the plugin should contain the following fields:
Field | Value |
---|
dependents | List of space separated plugins on which our plugin depends. (for names with spaces, use square brackets) |
description | Plugin description |
plugin-type | For the usual plugin “plugin”, for the theme “theme”, and for the language pack “language” |
type | Set "application / json" |
version | Plugin version number (for example, "0.0.1") |
Fill in the fields, and in the body of the plugin we write:
{"tiddlers": {}}

Keep tiddler. A third of the work is done.
We do the same with the second link, the macro script. Click on it, click "Edit", fill in the fields:
Field | Value |
---|
type | "Application / javascript" |
module-type | "Macro" |
Now the script body itself (under the spoiler):
Show code (function(){ "use strict"; exports.name = "progressbar"; exports.params = [ {name: "count"}, {name: "total"}, {name: "width", default: ""}, {name: "color", default: "green"}, {name: "title", default: "{count} {total}"} ]; exports.run = function(count, total, width, color, title) { count = parseInt(count); total = parseInt(total); width = (width == '') ? total * 10 : parseInt(width); var html = [svg(width), '<g>', tagTitle(count, total, title), innerRect(count, total, width, color), outerRect(width), '</g>', '</svg>']; return html.join("\n"); }; function svg(width) { width += 5; return '<svg width="' + width + '" height="15">'; }; function rect(width, fill) { return '<rect x="1.5" y="4.5" height="10" width="' + width + '" rx="3" ry="3" style="fill: ' + fill + '; stroke: green" />'; }; function outerRect(width) { return rect(width, 'none'); }; function innerRect(count, total, width, color) { var dx = 0; if (count > 0 && count != total) { dx = count * width / total; } else if (count == total) { dx = width; } return rect(dx, color); }; function tagTitle(count, total, title) { if (title == '') return ''; return '<title>' + title.replace('{count}', count).replace('{total}', total) + '</title>'; }; })();
I am not a real javascript, I write in this language occasionally, because the idiotic syntax with curly braces really annoys me. And in general, this is just an example of writing a plugin.
In general, we keep ready tiddler. Everything you need is already written. But it does not work, because it is not executed.
And now -
magic! Open the JavaScript console in the browser and write there this:
$tw.utils.repackPlugin('$:/plugins/morthan/progress', ['$:/plugins/morthan/progress/progressbar.js'])
The first argument is the name of the plugin to be repackaged. The second is a list of tiddler to be included in the plugin. Press
Enter . The browser says that everything went well and in order for the changes to take effect, you must save and reload the wiki.
So do. After the rediscovery in the HelloThere
tiddler , a beautiful green progress
bar suddenly appears.
Conclusion
The new version of TiddlyWiki has the opportunity to write plug-ins directly without leaving
the browser
pool . This allows you to creatively modify the system for yourself, opens up unlimited horizons and brings us closer to world domination by another small step.
PS: I'm not sure about the choice of hubs, because I don’t quite understand why they are needed. If I did something wrong, I will be grateful for clarifications in the comments.