1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-19 16:24:51 +00:00

Introduce genesis widget for dynamically creating widgets

See the "RedefineLet" test for a contrived example of usage
This commit is contained in:
jeremy@jermolene.com 2022-05-03 12:55:10 +01:00
parent e1df50d981
commit 56c2242e4e
6 changed files with 209 additions and 0 deletions

View File

@ -0,0 +1,100 @@
/*\
title: $:/core/modules/widgets/genesis.js
type: application/javascript
module-type: widget
Genesis widget for dynamically creating widgets
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
var GenesisWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/*
Inherit from the base widget class
*/
GenesisWidget.prototype = new Widget();
/*
Render this widget into the DOM
*/
GenesisWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.renderChildren(parent,nextSibling);
};
/*
Compute the internal state of the widget
*/
GenesisWidget.prototype.execute = function() {
var self = this;
// Collect attributes
this.genesisType = this.getAttribute("$type","element");
this.genesisTag = this.getAttribute("$tag","div");
this.genesisNames = this.getAttribute("$names","");
this.genesisValues = this.getAttribute("$values","");
// Construct parse tree
var parseTreeNodes = [{
type: this.genesisType,
tag: this.genesisTag,
attributes: {},
orderedAttributes: [],
children: this.parseTreeNode.children || []
}];
// Apply attributes in $names/$values
this.attributeNames = [];
this.attributeValues = [];
if(this.genesisNames && this.genesisValues) {
this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this);
this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this);
$tw.utils.each(this.attributeNames,function(varname,index) {
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || "");
});
}
// Apply explicit attributes
$tw.utils.each(this.attributes,function(value,name) {
if(name.charAt(0) === "$") {
if(name.charAt(1) === "$") {
// Double $$ is changed to a single $
name = name.substr(1);
} else {
// Single dollar is ignored
return;
}
}
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],name,value);
});
// Construct the child widgets
this.makeChildWidgets(parseTreeNodes);
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
GenesisWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes(),
filterNames = this.getAttribute("$names",""),
filterValues = this.getAttribute("$values",""),
attributeNames = this.wiki.filterTiddlers(filterNames,this),
attributeValues = this.wiki.filterTiddlers(filterValues,this);
if($tw.utils.count(changedAttributes) > 0 || !$tw.utils.isArrayEqual(this.attributeNames,attributeNames) || !$tw.utils.isArrayEqual(this.attributeValues,attributeValues)) {
this.refreshSelf();
return true;
} else {
return this.refreshChildren(changedTiddlers);
}
};
exports.genesis = GenesisWidget;
})();

View File

@ -0,0 +1,14 @@
title: Genesis/DollarSigns
description: Usage of genesis widget with attributes starting with dollar signs
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<$genesis $type="let" myvar="Kitten">(<$text text=<<myvar>>/>)</$genesis>
<$genesis $type="let" $$myvar="Kitten">(<$text text=<<$myvar>>/>)</$genesis>
_
title: ExpectedResult
<p>(Kitten)(Kitten)</p>

View File

@ -0,0 +1,14 @@
title: Genesis/MultipleAttributes
description: Usage of genesis widget with multiple attributes
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<$genesis $type="let" $names="myvar other" $values="Kitten Donkey" myvar="Shark">(<$text text=<<myvar>>/>|<$text text=<<other>>/>)</$genesis>
<$genesis $type="let" $names="$myvar $other" $values="Kitten Donkey" $$myvar="Shark">(<$text text=<<$myvar>>/>|<$text text=<<$other>>/>)</$genesis>
_
title: ExpectedResult
<p>(Shark|Donkey)(Shark|Donkey)</p>

View File

@ -0,0 +1,33 @@
title: Genesis/RedefineLet
description: Using the genesis widget to override the let widget
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
\function <$let>
\whitespace trim
<$setmultiplevariables $names="[enlist<paramNames>]" $values="[enlist<paramValues>addprefix[--]addsuffix[--]]">
<$slot $name="ts-body"/>
</$setmultiplevariables>
\end
<$let
one="Elephant"
$two="Kangaroo"
$$three="Giraffe"
>
(<$text text=<<one>>/>)
(<$text text=<<$two>>/>)
(<$text text=<<$$three>>/>)
</$let>
_
title: Definition
\whitespace trim
_
title: ExpectedResult
<p>(--Elephant--)
(--Kangaroo--)
(--Giraffe--)</p>

View File

@ -0,0 +1,14 @@
title: Genesis/Simple
description: Simple usage of genesis widget
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<$genesis $tag="div">Mouse</$genesis>
<$genesis $tag="div" class="tc-thing" label="Squeak">Mouse</$genesis>
_
title: ExpectedResult
<p><div>Mouse</div><div class="tc-thing" label="Squeak">Mouse</div></p>

View File

@ -0,0 +1,34 @@
caption: genesis
created: 20220502144738010
modified: 20220502144738010
tags: Widgets
title: GenesisWidget
type: text/vnd.tiddlywiki
! Introduction
<<.from-version "5.2.3">> The genesis widget allows the dynamic construction of widgets, where the name and attributes of the widget can be dynamically determined, and do not need to be known in advance.
! Content and Attributes
The content of the `<$genesis>` widget is used as the content of the dynamically created widget.
|!Attribute |!Description |
|$type |The type of widget to create |
|$tag |The HTML tag to be used for "element" widgets |
|$names |An optional filter evaluating to the names of a list of variables to be applied to the widget |
|$values |An optional filter evaluating to the values corresponding to the list of names specified in `$names` |
|//{other attributes starting with $}// |Other attributes starting with a single dollar sign are reserved for future use |
|//{attributes starting with $$}// |Attributes starting with two dollar signs are appplied as attributes to the output widget, but with the attribute name changed to use a single dollar sign |
|//{attributes not starting with $}// |Any other attributes that do not start with a dollar are applied as attributes to the output widget |
Note that attributes explicitly specified take precedence over attributes with the same name specified in the `$names` filter.
! Examples
<$macrocall $name='wikitext-example-without-html'
src='<$set name="myTiddler" value="HelloThere">
<$set name="myVariable" tiddler=<<myTiddler>> field={{$:/docs/anyField!!field}}>
<$text text=<<myVariable>>/>
</$set>
</$set>'/>