Introduction
Until now the examples have covered only simple, leaf widgets, but widgets can be arranged into a hierarchy. Compared to a leaf-only widget, widget classes which support having children must contain code to instantiate the children.
Not all widgets need to support having children. Widgets whose only purpose is to integrate third party javascript libraries, for example may not need it.
wiki text ⇨ parse tree ⇨ widget tree ⇨ DOM tree
- wiki text - Users write content in tiddlers using wiki text.
- parse tree - A parse tree is a JSON data structure describing the wiki text. Wiki text can be converted into a parse tree using
this.wiki.parseText
. - widget tree - Most items in the parse tree correspond to one or more items in the widget tree. The
this.makeChildWidgets
method is used to convert the parse tree into a widget tree. - DOM tree - A DOM tree is a standard javascript datastructure used by browsers to display a web page. The
this.renderChildren
method is used to instantiate the widget class and then render each widget in the widget tree. If a given widget will be visible in the browser, then one or more DOM nodes will be created.
Examples
Simple trees without nesting
Widgets in wiki text have a syntax similar to html (i.e. <$list/>
). But all wiki markup is seen by the tiddlywiki code as widgets.
Even a simple string with no special syntax will be treated as a widget. In this case a widget of type text
:
wiki text | html | renders as |
---|---|---|
hello |
hello | hello |
parse tree | widget tree |
---|---|
|
|
The above bare string of text is mostly just a synonym for this widget syntax:
wiki text | html | renders as |
---|---|---|
<$text text=hello/> |
hello | hello |
parse tree | widget tree |
---|---|
|
|
Some of the details of the parseTree and widgetTree are different in the two examples, but the general structure is the same and the rendered output is the same.
In these two simple examples, there is no nesting and so no child widgets are created.
Trees with one level of nesting
This next example shows the structure for bold wiki syntax. It is still simple, but does introduce one level of nesting: element
→text
The wiki syntax for bold converts to the standard html element strong
. Any standard html element is represented in tiddlywiki as a widget of type element
:
wiki text | html | renders as |
---|---|---|
''bold'' |
<strong>bold</strong> | bold |
parse tree | widget tree |
---|---|
|
|
Another example showing one level of nesting (link
→text
):
wiki text | html | renders as |
---|---|---|
<$link to=atiddler>link</$link> |
<a class="tc-tiddlylink tc-tiddlylink-missing" href="atiddler.html">link</a> | link |
parse tree | widget tree |
---|---|
|
|
Widgets with no DOM contribution
Not all widgets contribute items to the DOM. The purpose of some widgets is to affect the display of descendant widgets by changing some state. The $set
widget for example sets a variable which will be accessible to the descendant widgets:
wiki text | html | renders as |
---|---|---|
<$set name=myvar value=hi/> |
parse tree | widget tree |
---|---|
|
|
Nothing is rendered and there is no html, but the parse tree and widget tree contain information about the variable.
Dynamic widget children using this.wiki.parseText
In all the examples so far, there has been a close mapping between the nesting structure of the parse tree and the widget tree. If the item is in the parse tree, then it is in the widget tree. If the parse tree item has children, then the widget tree has the same number of children.
However, there are several examples of widgets in which more levels of nesting are created dynamically during the widget rendering process
The $macrocall
widget is one example:
wiki text | html | renders as |
---|---|---|
<$macrocall $name=now/> |
08:15, 21st November 2024 | 08:15, 21st November 2024 |
parse tree | widget tree |
---|---|
|
|
The parse tree has just a single type=$macrocall element with no children. The widget tree has that same type=$macrocall element, but it also has a child widget which wasn't in the parse tree.
In all cases, the $macrocall
widget calls the given macro and then calls this.wiki.parseText
on the output. This results in a new parse tree which is used to make the child widgets.
In this particular case, the now
macro is called. It returns a simple string of text, so when it is parsed the result causes the creation of a single child text widget containing the current date and time.
Widgets which do not support nesting
Just as some widgets can cause widget trees to have more nesting than the parse tree, some widgets can cause widget trees to have less nesting.
This happens when there is no use for the widget to have any children. The $text
widget, for example, has no use for displaying any descendants.
This behavior is accomplished by not calling the makeChildWidgets
method. Without that method call, the child widgets are not created from the child parse tree items. For example:
wiki text | html | renders as |
---|---|---|
<$text text="hi">ignored child text</$text> |
hi | hi |
parse tree | widget tree |
---|---|
|
|
Since the $text
widget does not have a call to makeChildWidgets
, 'ignored child text' above is present in the parse tree, but not in the widget tree.
Reference
method | when to call | what it does |
---|---|---|
makeChildWidgets | directly or indirectly from render method | converts child parse tree items into widget tree items |
renderChildren | directly or indirectly from render method, after the makeChildWidgets call | calls the render method of the child widget |
refreshChildren | directly or indirectly from refresh method, only needed if refreshSelf is not called | calls the refresh method of of the child widgets so they can check if refresh is needed |
this.wiki.parseText | pass the output parse tree to makeChildWidgets | converts the given text to a parse tree...only needed for dynamically constructed parsetree |
example call | purpose | widgets using this approach |
---|---|---|
this.makeChildWidgets() | construct child widgets from the static parse tree | $link, $button, etc. |
this.makeChildWidgets(parseTreeNodes) | construct child widgets from a dynamic parse tree | $list, $transclude, $macrocall, etc |
this.renderChildren(parent, nextSibling) | when the widget adds nothing to the dom, just pass the render arguments through to the children | $set, $importvariables, $tiddler, $wikify, etc. |
this.renderChildren(domNode, null) | passes the dom node generated by this widget into the children | $link, $button, etc |