mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-22 19:04:38 +00:00
Compare commits
13 Commits
fix-browse
...
dynamic-ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ebf60a05 | ||
|
|
5d72fb0608 | ||
|
|
30e6092819 | ||
|
|
4305a0bb92 | ||
|
|
b3144300ee | ||
|
|
205e8cf9c9 | ||
|
|
ad4c1ca5a1 | ||
|
|
5136e33f07 | ||
|
|
744f6e7a3b | ||
|
|
1ded43f6ea | ||
|
|
48e6863a89 | ||
|
|
f5d5a23aff | ||
|
|
2d6b6b5011 |
7
community/project/teams/Newsletter Team.tid
Normal file
7
community/project/teams/Newsletter Team.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: Newsletter Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
leader: @Christian_Byron
|
||||
|
||||
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.
|
||||
@@ -1,15 +0,0 @@
|
||||
title: TiddlyWiki Newsletter Team
|
||||
tags: Community/Team
|
||||
modified: 20251219090709874
|
||||
created: 20250909171928024
|
||||
leader: @Christian_Byron
|
||||
|
||||
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
|
||||
|
||||
! Audience
|
||||
|
||||
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
|
||||
|
||||
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
|
||||
|
||||
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.
|
||||
@@ -107,13 +107,14 @@ exports.parseStringLiteral = function(source,pos) {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')/g;
|
||||
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[([^\]]*)\]\]/g;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] !== undefined ? match[1] :(
|
||||
match[2] !== undefined ? match[2] : match[3]
|
||||
);
|
||||
match[2] !== undefined ? match[2] : (
|
||||
match[3] !== undefined ? match[3] : match[4]
|
||||
));
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
@@ -206,28 +207,164 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
|
||||
var node = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(node) {
|
||||
var positionalName = 0,
|
||||
transclusion = {
|
||||
type: "transclude",
|
||||
start: node.start,
|
||||
end: node.end
|
||||
};
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
|
||||
$tw.utils.each(node.params,function(param) {
|
||||
var name = param.name;
|
||||
if(name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
|
||||
} else {
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
|
||||
}
|
||||
});
|
||||
return transclusion;
|
||||
// console.log("parseMacroInvocationAsTransclusion",source,pos);
|
||||
var node = {
|
||||
type: "transclude",
|
||||
start: pos,
|
||||
attributes: {},
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reVarName = /([^\s>"'=:]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double opening angle bracket
|
||||
var token = $tw.utils.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
// console.log("No opening << in",source,"at",pos);
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the variable name for the macro
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
|
||||
if(!token) {
|
||||
// console.log("No macro name");
|
||||
return null;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
|
||||
pos = token.end;
|
||||
// Check that the tag is terminated by a space or >>
|
||||
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
|
||||
// console.log("No space or >> after macro name");
|
||||
return null;
|
||||
}
|
||||
// Process attributes
|
||||
pos = $tw.utils.parseMacroParametersAsAttributes(node,source,pos);
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double closing angle bracket
|
||||
token = $tw.utils.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
// console.log("No closing >>");
|
||||
return null;
|
||||
}
|
||||
node.end = token.end;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse macro parameters as attributes. Returns the position after the last attribute
|
||||
*/
|
||||
exports.parseMacroParametersAsAttributes = function(node,source,pos) {
|
||||
var position = 0,
|
||||
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
|
||||
while(attribute) {
|
||||
if(!attribute.name) {
|
||||
attribute.name = (position++) + "";
|
||||
attribute.isPositional = true;
|
||||
}
|
||||
node.orderedAttributes.push(attribute);
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
|
||||
}
|
||||
node.end = pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse a macro parameter as an attribute. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}, with the name being optional
|
||||
*/
|
||||
exports.parseMacroParameterAsAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'`=:]+)/g,
|
||||
reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/g,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g,
|
||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name and the separator token
|
||||
var nameToken = $tw.utils.parseTokenRegExp(source,pos,reAttributeName),
|
||||
namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end),
|
||||
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/g);
|
||||
// console.log(`parseMacroParametersAtAttribute source is ${source} at ${pos} and namepos is ${namePos} with nameToken as ${JSON.stringify(nameToken)} and separatorToken as ${JSON.stringify(separatorToken)}`);
|
||||
// If we have a name and a separator then we have a named attribute
|
||||
if(nameToken && separatorToken) {
|
||||
node.name = nameToken.match[1];
|
||||
// key value separator is `=` or `:`
|
||||
node.assignmentOperator = separatorToken.match[0];
|
||||
pos = separatorToken.end;
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
// Mark the value as having been quoted in the source
|
||||
node.quoted = true;
|
||||
} else {
|
||||
// console.log(`Failed to parse string literal ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
// Look for a filtered value
|
||||
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
|
||||
if(filteredValue) {
|
||||
pos = filteredValue.end;
|
||||
node.type = "filtered";
|
||||
node.filter = filteredValue.match[1];
|
||||
} else {
|
||||
// console.log(`Failed to parse filtered value ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// console.log(`Failed to parse indirect value ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
// console.log(`Parsed unquoted value ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
} else {
|
||||
// console.log(`Failed to parse unquoted value ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
// console.log(`Parsed macro invocation ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
} else {
|
||||
// console.log(`Failed to parse macro invocation ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
|
||||
if(substitutedValue) {
|
||||
pos = substitutedValue.end;
|
||||
node.type = "substituted";
|
||||
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
|
||||
} else {
|
||||
// console.log(`Failed to parse substituted value ${source} at ${pos} with node as ${JSON.stringify(node)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bail if we don't have a value
|
||||
if(!node.type) {
|
||||
return null;
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
@@ -296,7 +433,7 @@ exports.parseFilterVariable = function(source) {
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
@@ -354,7 +491,7 @@ exports.parseAttribute = function(source,pos) {
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
@@ -375,6 +512,7 @@ exports.parseAttribute = function(source,pos) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there is no equals sign or colon, then this is an attribute with no value, defaulting to "true"
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
|
||||
@@ -89,33 +89,13 @@ RevealWidget.prototype.positionPopup = function(domNode) {
|
||||
top = this.popup.top + this.popup.height;
|
||||
break;
|
||||
}
|
||||
// if requested, clamp the popup so that it will always be fully inside its parent (the first upstream element with position:relative), as long as the popup is smaller than its parent
|
||||
// if position is absolute then clamping is done to the canvas boundary, since there is no "parent"
|
||||
if(this.clampToParent !== "none") {
|
||||
if(this.popup.absolute) {
|
||||
var parentWidth = window.innerWidth,
|
||||
parentHeight = window.innerHeight;
|
||||
} else {
|
||||
var parentWidth = domNode.offsetParent.offsetWidth,
|
||||
parentHeight = domNode.offsetParent.offsetHeight;
|
||||
}
|
||||
var right = left + domNode.offsetWidth,
|
||||
bottom = top + domNode.offsetHeight;
|
||||
if((this.clampToParent === "both" || this.clampToParent === "right") && right > parentWidth) {
|
||||
left = parentWidth - domNode.offsetWidth;
|
||||
}
|
||||
if((this.clampToParent === "both" || this.clampToParent === "bottom") && bottom > parentHeight) {
|
||||
top = parentHeight - domNode.offsetHeight;
|
||||
}
|
||||
// clamping on left and top sides is taken care of by positionAllowNegative
|
||||
}
|
||||
if(!this.positionAllowNegative) {
|
||||
left = Math.max(0,left);
|
||||
top = Math.max(0,top);
|
||||
}
|
||||
if(this.popup.absolute) {
|
||||
if (this.popup.absolute) {
|
||||
// Traverse the offsetParent chain and correct the offset to make it relative to the parent node.
|
||||
for(var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
|
||||
for (var offsetParentDomNode = domNode.offsetParent; offsetParentDomNode; offsetParentDomNode = offsetParentDomNode.offsetParent) {
|
||||
left -= offsetParentDomNode.offsetLeft;
|
||||
top -= offsetParentDomNode.offsetTop;
|
||||
}
|
||||
@@ -143,7 +123,6 @@ RevealWidget.prototype.execute = function() {
|
||||
this.openAnimation = this.animate === "no" ? undefined : "open";
|
||||
this.closeAnimation = this.animate === "no" ? undefined : "close";
|
||||
this.updatePopupPosition = this.getAttribute("updatePopupPosition","no") === "yes";
|
||||
this.clampToParent = this.getAttribute("clamp","none");
|
||||
// Compute the title of the state tiddler and read it
|
||||
this.stateTiddlerTitle = this.state;
|
||||
this.stateTitle = this.getAttribute("stateTitle");
|
||||
@@ -162,7 +141,7 @@ Read the state tiddler
|
||||
RevealWidget.prototype.readState = function() {
|
||||
// Read the information from the state tiddler
|
||||
var state,
|
||||
defaultState = this["default"];
|
||||
defaultState = this["default"];
|
||||
if(this.stateTitle) {
|
||||
var stateTitleTiddler = this.wiki.getTiddler(this.stateTitle);
|
||||
if(this.stateField) {
|
||||
@@ -284,7 +263,7 @@ RevealWidget.prototype.updateState = function() {
|
||||
} else {
|
||||
$tw.anim.perform(this.closeAnimation,domNode,{callback: function() {
|
||||
//make sure that the state hasn't changed during the close animation
|
||||
self.readState();
|
||||
self.readState()
|
||||
if(!self.isOpen) {
|
||||
domNode.setAttribute("hidden","true");
|
||||
}
|
||||
|
||||
@@ -414,7 +414,21 @@ Widget.prototype.computeAttribute = function(attribute,options) {
|
||||
value = [value];
|
||||
}
|
||||
} else if(attribute.type === "macro") {
|
||||
var variableInfo = this.getVariableInfo(attribute.value.name,{params: attribute.value.params});
|
||||
// Get the macro name
|
||||
var macroName = attribute.value.attributes["$variable"].value;
|
||||
// Collect macro parameters
|
||||
var params = [];
|
||||
$tw.utils.each(attribute.value.orderedAttributes,function(attr) {
|
||||
var param = {
|
||||
value: self.computeAttribute(attr)
|
||||
};
|
||||
if(attr.name && !attr.isPositional) {
|
||||
param.name = attr.name;
|
||||
}
|
||||
params.push(param);
|
||||
});
|
||||
// Invoke the macro
|
||||
var variableInfo = this.getVariableInfo(macroName,{params: params});
|
||||
if(options.asList) {
|
||||
value = variableInfo.resultList;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
title: Macros/Dynamic/Attribute
|
||||
description: Attribute macrocall with dynamic paramters
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\define mamacromamacro(param:"red")
|
||||
It is $param$
|
||||
\end
|
||||
|
||||
<$text text=<<mamacromamacro>>/>
|
||||
-
|
||||
<$text text=<<mamacromamacro param:{{{ [[a]addprefix[b]] }}}>>/>
|
||||
-
|
||||
<$text text=<<mamacromamacro param={{{ [[b]addprefix[a]] }}}>>/>
|
||||
-
|
||||
<$text text=<<mamacromamacro {{{ [[b]addprefix[a]] }}}>>/>
|
||||
-
|
||||
<$text text=<<mamacromamacro param>>/>
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>It is red
|
||||
-
|
||||
It is ba
|
||||
-
|
||||
It is ab
|
||||
-
|
||||
It is ab
|
||||
-
|
||||
It is param
|
||||
</p>
|
||||
@@ -0,0 +1,26 @@
|
||||
title: Macros/Dynamic/Standalone
|
||||
description: Standalone macrocall with dynamic paramters
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\define mamacro(one:"red",two:"green")
|
||||
It is $one$ and $two$ or <<__one__>> and <<__two__>>.
|
||||
\end
|
||||
|
||||
<<mamacro>>
|
||||
|
||||
<<mamacro one:{{{ [[a]addprefix[b]] }}}>>
|
||||
|
||||
<<mamacro one={{{ [[b]addprefix[a]] }}}>>
|
||||
|
||||
<<mamacro {{{ [[b]addprefix[a]] }}}>>
|
||||
|
||||
<<mamacro one>>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>It is red and green or red and green.</p><p>It is ba and green or ba and green.</p><p>It is ab and green or ab and green.</p><p>It is ab and green or ab and green.</p><p>It is one and green or one and green.</p>
|
||||
@@ -0,0 +1,9 @@
|
||||
tags: $:/tags/wikitext-serialize-test-spec
|
||||
title: Serialize/DynamicMacroMixed
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<mymacro static:"value" dynamic={{reference}} filter={{{ [tag[test]] }}}>>
|
||||
|
||||
<$macrocall $name="mymacro" static="value" dynamic=<<inner>>/>
|
||||
|
||||
<<mymacro `substituted $(var)$`>>
|
||||
@@ -0,0 +1,9 @@
|
||||
tags: $:/tags/wikitext-serialize-test-spec
|
||||
title: Serialize/DynamicMacroParams
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<mymacro param={{Something}}>>
|
||||
|
||||
<<mymacro param={{{ [<myvar>addprefix[https:]] }}}>>
|
||||
|
||||
<$macrocall $name="outermacro" inner=<<innermacro arg="value">>/>
|
||||
@@ -0,0 +1,7 @@
|
||||
tags: $:/tags/wikitext-serialize-test-spec
|
||||
title: Serialize/DynamicWidgetAttribute
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<div class=<<mymacro param={{Something}}>>>content</div>
|
||||
|
||||
<$button actions=<<myactions target={{!!title}}>>/>
|
||||
@@ -7,3 +7,7 @@ type: text/vnd.tiddlywiki
|
||||
<<.def "macro calls">>
|
||||
|
||||
<<alert "primary" "primary alert" width:"60%">>
|
||||
|
||||
<<john one:val1 two:val2 three:"quoted value">>
|
||||
|
||||
<<test unquoted:value quoted:"value" number:123>>
|
||||
|
||||
@@ -3,3 +3,5 @@ title: Serialize/MacroCallInline
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
These are macro calls in a line: <<name "value" "value2">> and <<.def "macro calls">> <<alert "primary" "primary alert" width:"60%">>
|
||||
|
||||
Testing unquoted parameters: <<john one:val1 two:val2>> and <<test param:value other:"quoted">>.
|
||||
|
||||
@@ -235,11 +235,307 @@ describe("HTML tag new parser tests", function() {
|
||||
expect(parser.parseTag("< $mytag attrib1='something' attrib2=else thing>",0)).toEqual(
|
||||
null
|
||||
);
|
||||
expect(parser.parseTag("<$mytag attrib3=<<myMacro one:two three:'four and five'>>>",0)).toEqual(
|
||||
{ type : "mytag", start : 0, attributes : { attrib3 : { type : "macro", start : 7, name : "attrib3", value : { type : "macrocall", start : 16, params : [ { type : "macro-parameter", start : 25, value : "two", name : "one", end : 33 }, { type : "macro-parameter", start : 33, value : "four and five", name : "three", end : 55 } ], name : "myMacro", end : 57 }, end : 57 } }, orderedAttributes: [ { type : "macro", start : 7, name : "attrib3", value : { type : "macrocall", start : 16, params : [ { type : "macro-parameter", start : 25, value : "two", name : "one", end : 33 }, { type : "macro-parameter", start : 33, value : "four and five", name : "three", end : 55 } ], name : "myMacro", end : 57 }, end : 57 } ], tag : "$mytag", end : 58 }
|
||||
expect(parser.parseTag("<$mytag attrib3=<<myMacro one:two three:'four and five'>>>", 0)).toEqual(
|
||||
{
|
||||
"type": "mytag",
|
||||
"start": 0,
|
||||
"attributes": {
|
||||
"attrib3": {
|
||||
"start": 7,
|
||||
"name": "attrib3",
|
||||
"type": "macro",
|
||||
"value": {
|
||||
"type": "transclude",
|
||||
"start": 16,
|
||||
"attributes": {
|
||||
"$variable": {
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
"one": {
|
||||
"start": 25,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 33
|
||||
},
|
||||
"three": {
|
||||
"start": 33,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 55
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
{
|
||||
"start": 25,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 33
|
||||
},
|
||||
{
|
||||
"start": 33,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 55
|
||||
}
|
||||
],
|
||||
"end": 57
|
||||
},
|
||||
"end": 57
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"start": 7,
|
||||
"name": "attrib3",
|
||||
"type": "macro",
|
||||
"value": {
|
||||
"type": "transclude",
|
||||
"start": 16,
|
||||
"attributes": {
|
||||
"$variable": {
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
"one": {
|
||||
"start": 25,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 33
|
||||
},
|
||||
"three": {
|
||||
"start": 33,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 55
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
{
|
||||
"start": 25,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 33
|
||||
},
|
||||
{
|
||||
"start": 33,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 55
|
||||
}
|
||||
],
|
||||
"end": 57
|
||||
},
|
||||
"end": 57
|
||||
}
|
||||
],
|
||||
"tag": "$mytag",
|
||||
"end": 58
|
||||
}
|
||||
);
|
||||
expect(parser.parseTag("<$mytag attrib1='something' attrib2=else thing attrib3=<<myMacro one:two three:'four and five'>>>",0)).toEqual(
|
||||
{ type : "mytag", start : 0, attributes : { attrib1 : { type : "string", start : 7, name : "attrib1", value : "something", end : 27 }, attrib2 : { type : "string", start : 27, name : "attrib2", value : "else", end : 40 }, thing : { type : "string", start : 40, name : "thing", value : "true", end : 47 }, attrib3 : { type : "macro", start : 47, name : "attrib3", value : { type : "macrocall", start : 55, params : [ { type : "macro-parameter", start : 64, value : "two", name : "one", end : 72 }, { type : "macro-parameter", start : 72, value : "four and five", name : "three", end : 94 } ], name : "myMacro", end : 96 }, end : 96 } }, orderedAttributes: [ { type : "string", start : 7, name : "attrib1", value : "something", end : 27 }, { type : "string", start : 27, name : "attrib2", value : "else", end : 40 }, { type : "string", start : 40, name : "thing", value : "true", end : 47 }, { type : "macro", start : 47, name : "attrib3", value : { type : "macrocall", start : 55, params : [ { type : "macro-parameter", start : 64, value : "two", name : "one", end : 72 }, { type : "macro-parameter", start : 72, value : "four and five", name : "three", end : 94 } ], name : "myMacro", end : 96 }, end : 96 } ], tag : "$mytag", end : 97 }
|
||||
{
|
||||
"type": "mytag",
|
||||
"start": 0,
|
||||
"attributes": {
|
||||
"attrib1": {
|
||||
"start": 7,
|
||||
"name": "attrib1",
|
||||
"type": "string",
|
||||
"value": "something",
|
||||
"end": 27
|
||||
},
|
||||
"attrib2": {
|
||||
"start": 27,
|
||||
"name": "attrib2",
|
||||
"type": "string",
|
||||
"value": "else",
|
||||
"end": 40
|
||||
},
|
||||
"thing": {
|
||||
"start": 40,
|
||||
"name": "thing",
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
"end": 47
|
||||
},
|
||||
"attrib3": {
|
||||
"start": 47,
|
||||
"name": "attrib3",
|
||||
"type": "macro",
|
||||
"value": {
|
||||
"type": "transclude",
|
||||
"start": 55,
|
||||
"attributes": {
|
||||
"$variable": {
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
"one": {
|
||||
"start": 64,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 72
|
||||
},
|
||||
"three": {
|
||||
"start": 72,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 94
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
{
|
||||
"start": 64,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 72
|
||||
},
|
||||
{
|
||||
"start": 72,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 94
|
||||
}
|
||||
],
|
||||
"end": 96
|
||||
},
|
||||
"end": 96
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"start": 7,
|
||||
"name": "attrib1",
|
||||
"type": "string",
|
||||
"value": "something",
|
||||
"end": 27
|
||||
},
|
||||
{
|
||||
"start": 27,
|
||||
"name": "attrib2",
|
||||
"type": "string",
|
||||
"value": "else",
|
||||
"end": 40
|
||||
},
|
||||
{
|
||||
"start": 40,
|
||||
"name": "thing",
|
||||
"type": "string",
|
||||
"value": "true",
|
||||
"end": 47
|
||||
},
|
||||
{
|
||||
"start": 47,
|
||||
"name": "attrib3",
|
||||
"type": "macro",
|
||||
"value": {
|
||||
"type": "transclude",
|
||||
"start": 55,
|
||||
"attributes": {
|
||||
"$variable": {
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
"one": {
|
||||
"start": 64,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 72
|
||||
},
|
||||
"three": {
|
||||
"start": 72,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 94
|
||||
}
|
||||
},
|
||||
"orderedAttributes": [
|
||||
{
|
||||
"name": "$variable",
|
||||
"type": "string",
|
||||
"value": "myMacro"
|
||||
},
|
||||
{
|
||||
"start": 64,
|
||||
"name": "one",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "two",
|
||||
"end": 72
|
||||
},
|
||||
{
|
||||
"start": 72,
|
||||
"name": "three",
|
||||
"assignmentOperator": ":",
|
||||
"type": "string",
|
||||
"value": "four and five",
|
||||
"quoted": true,
|
||||
"end": 94
|
||||
}
|
||||
],
|
||||
"end": 96
|
||||
},
|
||||
"end": 96
|
||||
}
|
||||
],
|
||||
"tag": "$mytag",
|
||||
"end": 97
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ describe("WikiText parser tests", function() {
|
||||
);
|
||||
expect(parse("text <<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual(
|
||||
|
||||
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":92,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":11,"end":20},"two":{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},"three":{"name":"three","type":"string","value":"val '3'","start":35,"end":52},"four":{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},"five":{"name":"five","type":"string","value":"val 5","start":73,"end":89}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":11,"end":20},{"name":"two","type":"string","value":"val \"2\"","start":20,"end":35},{"name":"three","type":"string","value":"val '3'","start":35,"end":52},{"name":"four","type":"string","value":"val 4\"5'","start":52,"end":73},{"name":"five","type":"string","value":"val 5","start":73,"end":89}]}],"start":0,"end":92}]
|
||||
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":92,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","assignmentOperator":":","type":"string","value":"val1","start":11,"end":20},"two":{"name":"two","assignmentOperator":":","type":"string","value":"val \"2\"","quoted":true,"start":20,"end":35},"three":{"name":"three","assignmentOperator":":","type":"string","value":"val '3'","quoted":true,"start":35,"end":52},"four":{"name":"four","assignmentOperator":":","type":"string","value":"val 4\"5'","quoted":true,"start":52,"end":73},"five":{"name":"five","assignmentOperator":":","type":"string","value":"val 5","quoted":true,"start":73,"end":89}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","assignmentOperator":":","type":"string","value":"val1","start":11,"end":20},{"name":"two","assignmentOperator":":","type":"string","value":"val \"2\"","quoted":true,"start":20,"end":35},{"name":"three","assignmentOperator":":","type":"string","value":"val '3'","quoted":true,"start":35,"end":52},{"name":"four","assignmentOperator":":","type":"string","value":"val 4\"5'","quoted":true,"start":52,"end":73},{"name":"five","assignmentOperator":":","type":"string","value":"val 5","quoted":true,"start":73,"end":89}]}],"start":0,"end":92}]
|
||||
|
||||
);
|
||||
expect(parse("ignored << carrots <<john>>")).toEqual(
|
||||
@@ -287,7 +287,7 @@ describe("WikiText parser tests", function() {
|
||||
);
|
||||
expect(parse("text <<outie one:'my <<innie>>' >>")).toEqual(
|
||||
|
||||
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":34,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"outie"},"one":{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","type":"string","value":"my <<innie>>","start":12,"end":31}]}],"start":0,"end":34}]
|
||||
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"text","text":"text ","start":0,"end":5},{"type":"transclude","start":5,"end":34,"rule":"macrocallinline","attributes":{"$variable":{"name":"$variable","type":"string","value":"outie"},"one":{"name":"one","assignmentOperator":":","type":"string","value":"my <<innie>>","quoted":true,"start":12,"end":31}},"orderedAttributes":[{"name":"$variable","type":"string","value":"outie"},{"name":"one","assignmentOperator":":","type":"string","value":"my <<innie>>","quoted":true,"start":12,"end":31}]}],"start":0,"end":34}]
|
||||
|
||||
);
|
||||
|
||||
@@ -301,7 +301,7 @@ describe("WikiText parser tests", function() {
|
||||
);
|
||||
expect(parse("<<john one:val1 two: 'val \"2\"' three: \"val '3'\" four: \"\"\"val 4\"5'\"\"\" five: [[val 5]] >>")).toEqual(
|
||||
|
||||
[{"type":"transclude","start":0,"end":87,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","type":"string","value":"val1","start":6,"end":15},"two":{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},"three":{"name":"three","type":"string","value":"val '3'","start":30,"end":47},"four":{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},"five":{"name":"five","type":"string","value":"val 5","start":68,"end":84}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","type":"string","value":"val1","start":6,"end":15},{"name":"two","type":"string","value":"val \"2\"","start":15,"end":30},{"name":"three","type":"string","value":"val '3'","start":30,"end":47},{"name":"four","type":"string","value":"val 4\"5'","start":47,"end":68},{"name":"five","type":"string","value":"val 5","start":68,"end":84}],"isBlock":true}]
|
||||
[{"type":"transclude","start":0,"end":87,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"john"},"one":{"name":"one","assignmentOperator":":","type":"string","value":"val1","start":6,"end":15},"two":{"name":"two","assignmentOperator":":","type":"string","value":"val \"2\"","quoted":true,"start":15,"end":30},"three":{"name":"three","assignmentOperator":":","type":"string","value":"val '3'","quoted":true,"start":30,"end":47},"four":{"name":"four","assignmentOperator":":","type":"string","value":"val 4\"5'","quoted":true,"start":47,"end":68},"five":{"name":"five","assignmentOperator":":","type":"string","value":"val 5","quoted":true,"start":68,"end":84}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"one","assignmentOperator":":","type":"string","value":"val1","start":6,"end":15},{"name":"two","assignmentOperator":":","type":"string","value":"val \"2\"","quoted":true,"start":15,"end":30},{"name":"three","assignmentOperator":":","type":"string","value":"val '3'","quoted":true,"start":30,"end":47},{"name":"four","assignmentOperator":":","type":"string","value":"val 4\"5'","quoted":true,"start":47,"end":68},{"name":"five","assignmentOperator":":","type":"string","value":"val 5","quoted":true,"start":68,"end":84}],"isBlock":true}]
|
||||
|
||||
);
|
||||
expect(parse("<< carrots\n\n<<john>>")).toEqual(
|
||||
@@ -321,12 +321,12 @@ describe("WikiText parser tests", function() {
|
||||
);
|
||||
expect(parse("<<multiline arg:\"\"\"\n\nwikitext\n\"\"\" >>")).toEqual(
|
||||
|
||||
[{"type":"transclude","start":0,"end":36,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"multiline"},"arg":{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}},"orderedAttributes":[{"name":"$variable","type":"string","value":"multiline"},{"name":"arg","type":"string","value":"\n\nwikitext\n","start":11,"end":33}],"isBlock":true}]
|
||||
[{"type":"transclude","start":0,"end":36,"rule":"macrocallblock","attributes":{"$variable":{"name":"$variable","type":"string","value":"multiline"},"arg":{"name":"arg","assignmentOperator":":","type":"string","value":"\n\nwikitext\n","quoted":true,"start":11,"end":33}},"orderedAttributes":[{"name":"$variable","type":"string","value":"multiline"},{"name":"arg","assignmentOperator":":","type":"string","value":"\n\nwikitext\n","quoted":true,"start":11,"end":33}],"isBlock":true}]
|
||||
|
||||
);
|
||||
expect(parse("<<outie one:'my <<innie>>' >>")).toEqual(
|
||||
|
||||
[ { type: "transclude", start: 0, rule: "macrocallblock", attributes: { $variable: {name: "$variable", type:"string", value: "outie"}, one: {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", type:"string", value: "my <<innie>>", start: 7, end: 26} ], end: 29, isBlock: true } ]
|
||||
[ { type: "transclude", start: 0, rule: "macrocallblock", attributes: { $variable: {name: "$variable", type:"string", value: "outie"}, one: {name: "one", assignmentOperator: ":", type:"string", value: "my <<innie>>", quoted: true, start: 7, end: 26} }, orderedAttributes: [ {name: "$variable", type:"string", value: "outie"}, {name: "one", assignmentOperator: ":", type:"string", value: "my <<innie>>", quoted: true, start: 7, end: 26} ], end: 29, isBlock: true } ]
|
||||
|
||||
);
|
||||
});
|
||||
@@ -334,23 +334,23 @@ describe("WikiText parser tests", function() {
|
||||
it("should parse tricky macrocall parameters", function() {
|
||||
expect(parse("<<john pa>am>>")).toEqual(
|
||||
|
||||
[{"type":"transclude","start":0,"end":14,"attributes":{"0":{"name":"0","type":"string","value":"pa>am","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"pa>am","start":6,"end":12}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
[{"type":"transclude","start":0,"end":14,"attributes":{"0":{"name":"0","type":"string","value":"pa>am","start":6,"end":12,"isPositional":true},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"pa>am","start":6,"end":12,"isPositional":true}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
|
||||
);
|
||||
expect(parse("<<john param> >>")).toEqual(
|
||||
|
||||
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"param>","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param>","start":6,"end":13}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"param>","start":6,"end":13,"isPositional":true},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param>","start":6,"end":13,"isPositional":true}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
|
||||
);
|
||||
expect(parse("<<john param>>>")).toEqual(
|
||||
|
||||
[{"type":"element","tag":"p",rule:"parseblock","children":[{"type":"transclude","start":0,"end":14,"rule":"macrocallinline","attributes":{"0":{"name":"0","type":"string","value":"param","start":6,"end":12},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param","start":6,"end":12}]},{"type":"text","text":">","start":14,"end":15}],"start":0,"end":15}]
|
||||
[{"type":"element","rule":"parseblock","tag":"p","children":[{"type":"transclude","start":0,"end":14,"rule":"macrocallinline","attributes":{"0":{"name":"0","type":"string","value":"param","start":6,"end":12,"isPositional":true},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"param","start":6,"end":12,"isPositional":true}]},{"type":"text","text":">","start":14,"end":15}],"start":0,"end":15}]
|
||||
|
||||
);
|
||||
// equals signs should be allowed
|
||||
expect(parse("<<john var>=4 >>")).toEqual(
|
||||
|
||||
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"var>=4","start":6,"end":13},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"var>=4","start":6,"end":13}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
[{"type":"transclude","start":0,"end":16,"attributes":{"0":{"name":"0","type":"string","value":"var>=4","start":6,"end":13,"isPositional":true},"$variable":{"name":"$variable","type":"string","value":"john"}},"orderedAttributes":[{"name":"$variable","type":"string","value":"john"},{"name":"0","type":"string","value":"var>=4","start":6,"end":13,"isPositional":true}],"isBlock":true,"rule":"macrocallblock"}]
|
||||
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
title: TiddlyWiki Newsletter Team
|
||||
modified: 20241009171916728
|
||||
tags: Community
|
||||
|
||||
The ~TiddlyWiki Newsletter is produced by a small team of volunteers. We would love to have your help if you want to get involved.
|
||||
|
||||
! Team
|
||||
|
||||
The newsletter team currently consists of:
|
||||
|
||||
* [[@jeremyruston|https://talk.tiddlywiki.org/u/jeremyruston]]
|
||||
* [[@CodaCoder|https://talk.tiddlywiki.org/u/codacoder]]
|
||||
* [[@Springer|https://talk.tiddlywiki.org/u/springer]]
|
||||
|
||||
! Audience
|
||||
|
||||
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
|
||||
|
||||
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
|
||||
|
||||
Subscribing to the newsletter should give people confidence that they will not miss any important developments.
|
||||
|
||||
! Process
|
||||
|
||||
The process is:
|
||||
|
||||
# Determine which discussion forum threads should be included
|
||||
# Decide whether to link to the thread itself or to link to the subject of the thread
|
||||
# Write a 30-70 word introduction
|
||||
# Optionally, choose or make an image/screenshot to illustrate the story
|
||||
|
||||
These steps are described in more detail below.
|
||||
|
||||
!! Criteria for Inclusion
|
||||
|
||||
The criteria for inclusion are necessarily loose. Editorial judgement is required to decide whether an item is sufficiently interesting to a broad enough audience.
|
||||
|
||||
Important categories of threads that should be considered:
|
||||
|
||||
* All announcements of new releases of TiddlyWiki and TiddlyDesktop
|
||||
* Community news and developments
|
||||
* New plugins
|
||||
* Updates to widely used plugins
|
||||
* Showcases of interesting TiddlyWiki's in the wild
|
||||
|
||||
!! Linking
|
||||
|
||||
In most cases, news items should link to the opening post in the corresponding thread. There might be situations where it makes more sense to link to the item concerned which will be listed here.
|
||||
|
||||
!! Writing News Items
|
||||
|
||||
Items would be a 30-70 word introduction with a link, and optionally an image (the newsletter looks much more inviting with some images included).
|
||||
|
||||
!! Images
|
||||
|
||||
Well chosen images can be informative and add visual interest to the newsletter as a whole. Some points to consider when choosing an image:
|
||||
|
||||
* Images that work best of all are those that trigger an emotional response by including a human face. It is fairly unlikely that a ~TiddlyWiki news story would have a reason to be illustrated by a picture of a smiling baby, but we should strive to do so if we can
|
||||
* If using a screenshot, remember that the image will be displayed fairly small in the newsletter so it is better to crop screenshots to show a smaller area of interest rather than the entire browser window
|
||||
* Avoid using AI generated images
|
||||
@@ -1,10 +1,10 @@
|
||||
title: TiddlyWiki Newsletter
|
||||
modified: 20251219090240895
|
||||
modified: 20241009171916728
|
||||
|
||||
The ~TiddlyWiki Newsletter is a collection of news, announcements and discussions from the ~TiddlyWiki community.
|
||||
The ~TiddlyWiki Newsletter is a fortnightly overview of news, announcements and discussions within the ~TiddlyWiki community. It has been on hiatus for the last few months, but we are hoping to revive it soon.
|
||||
|
||||
Subscribe here:
|
||||
Subscribe to the ~TiddlyWiki Newsletter here:
|
||||
|
||||
!! https://tiddlywiki.substack.com/
|
||||
<iframe src="https://tiddlywiki.substack.com/embed" width="480" height="320" style="border:1px solid #EEE; background:white;" frameborder="0" scrolling="no"></iframe>
|
||||
|
||||
The newsletter is produced by a small team of volunteers. We would welcome your help. See [[TiddlyWiki Newsletter Team]].
|
||||
The newsletter is produced by a small team of volunteers. We would welcome your help. See [[TiddlyWiki Newsletter Team]].
|
||||
@@ -6,4 +6,4 @@ image: TiddlyWiki Newsletter Badge
|
||||
color: #fff
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Subscribe to the ~TiddlyWiki Newsletter, a summary of the most interesting and relevant news from the ~TiddlyWiki community
|
||||
Subscribe to the ~TiddlyWiki Newsletter, a fortnightly summary of the most interesting and relevant news from the ~TiddlyWiki community
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 9.9 KiB |
@@ -1,11 +0,0 @@
|
||||
title: $:/changenotes/5.4.0/#7898
|
||||
description: Add clamp attribute to RevealWidget
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: widget
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/7898
|
||||
github-contributors: yaisog
|
||||
|
||||
The attribute `clamp` is added to the RevealWidget to force the popup to be displayed inside its container without overflowing. The value can be `right`, `bottom` or `both`.
|
||||
Clamping to left and top can be accomplished via the `positionAllowNegative` attribute.
|
||||
@@ -1,10 +0,0 @@
|
||||
title: $:/changenotes/5.4.0/#9538
|
||||
description: Fix browser storage plugin making wiki dirty
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: bugfix
|
||||
change-category: plugin
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9538
|
||||
github-contributors: Jermolene
|
||||
|
||||
Fixed issue where the browser storage plugin caused the wiki to be marked as dirty every time it starts up. The problem was due to the use of a log tiddler titled `$:/info/browser/storage/persisted`, the fix is to rename it to `$:/state/browser/storage/persisted`.
|
||||
@@ -0,0 +1,48 @@
|
||||
title: Improvements to Macro Calls in v5.4.0
|
||||
tags: v5.4.0
|
||||
|
||||
<$macrocall $name='wikitext-example-without-html'
|
||||
src="""\define testmacro(one)
|
||||
Result: $one$.
|
||||
\end testmacro
|
||||
|
||||
<<testmacro one={{{ [[There]addprefix[Hello]] }}}>>
|
||||
"""/>
|
||||
|
||||
<$macrocall $name='wikitext-example-without-html'
|
||||
src="""\function testfunction(one)
|
||||
[<one>addprefix[Hello]]
|
||||
\end testfunction
|
||||
|
||||
<<testfunction one={{{ [[re]addprefix[The]] }}}>>
|
||||
"""/>
|
||||
|
||||
<$macrocall $name='wikitext-example-without-html'
|
||||
src="""\define testmacro(one)
|
||||
Result: $one$.
|
||||
\end testmacro
|
||||
|
||||
<$text text=<<testmacro one={{{ [[There]addprefix[Hello]] }}}>>/>
|
||||
"""/>
|
||||
|
||||
<$macrocall $name='wikitext-example-without-html'
|
||||
src="""\function testfunction(one)
|
||||
[<one>addprefix[Hello]]
|
||||
\end testfunction
|
||||
|
||||
<$text text=<<testfunction one={{{ [[re]addprefix[The]] }}}>>/>
|
||||
"""/>
|
||||
|
||||
<$macrocall $name='wikitext-example'
|
||||
src="""\define innermacro(one)
|
||||
:$one$:$one$:
|
||||
\end innermacro
|
||||
|
||||
\define mymacro(param)
|
||||
|$param$|$param$|
|
||||
\end mymacro
|
||||
|
||||
<div class=<<mymacro param={{{ [<innermacro one={{$:/palette}}>addprefix[The palette named ]] }}}>>>
|
||||
Content
|
||||
</div>
|
||||
"""/>
|
||||
@@ -1,66 +1,49 @@
|
||||
caption: reveal
|
||||
created: 20131024141900000
|
||||
jeremy: tiddlywiki
|
||||
modified: 20251212091659847
|
||||
modified: 20250211091937860
|
||||
tags: Widgets
|
||||
title: RevealWidget
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
! Introduction
|
||||
|
||||
The reveal widget hides or shows its content depending upon the value of a [[state tiddler|StateMechanism]].
|
||||
The reveal widget hides or shows its content depending upon the value of a [[state tiddler|StateTiddler]]. The type of the widget determines the condition for the content being displayed:
|
||||
|
||||
* type=''match'': the content is displayed if the state tiddler matches the text attribute value
|
||||
* type=''nomatch'': the content is displayed if the state tiddler doesn't match the text attribute value
|
||||
* type=''popup'': the content is displayed as a popup as described in the PopupMechanism
|
||||
* type=''lt'': the content is displayed if the state tiddler contains an integer with a value ''less than'' the text attribute value
|
||||
* type=''gt'': the content is displayed if the state tiddler contains an integer with a value ''greater than'' the text attribute value
|
||||
* type=''lteq'': the content is displayed if the state tiddler contains an integer with a value ''less than or equal to'' the text attribute value
|
||||
* type=''gteq'': the content is displayed if the state tiddler contains an integer with a value ''greater than or equal to'' the text attribute value
|
||||
|
||||
|
||||
! Content and Attributes
|
||||
|
||||
The content of the `<$reveal>` widget is displayed according to the rules given above.
|
||||
|
||||
|!Attribute |!Description |
|
||||
|<<.attr state>> |A TextReference containing the state |
|
||||
|<<.attr stateTitle>> |A title containing the state, without TextReference. Gets preferred over the <<.attr state>> attribute if both are set |
|
||||
|<<.attr stateField>> |A field name which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|
||||
|<<.attr stateIndex>> |An index which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|
||||
|<<.attr default>> |Default value to use when the state tiddler is missing |
|
||||
|<<.attr tag>> |Overrides the default [[HTML tag|HTML Tags]] (`<div>` in block mode or `<span>` in inline mode) |
|
||||
|<<.attr type>> |The type of matching performed, see below |
|
||||
|<<.attr text>> |The text to match when the type is <<.value match>>, <<.value nomatch>>, <<.value lt>>, <<.value gt>>, <<.value lteq>> or <<.value gteq>> |
|
||||
|<<.attr class>> |An optional CSS class name to be assigned to the HTML element|
|
||||
|<<.attr style>> |An optional CSS style attribute to be assigned to the HTML element |
|
||||
|<<.attr position>> |The position used for the popup when the type is <<.value popup>>.<br> Can be <<.value left>>, <<.value above>>, <<.value aboveleft>>, <<.value aboveright>>, <<.value right>>, <<.value belowleft>>, <<.value belowright>> or <<.value below>>. Also see [[Popup Clamping Example|RevealWidget (Popup Clamping Example)]] |
|
||||
|<<.attr positionAllowNegative>> |Set to <<.value yes>> to allow computed popup positions to be negative relative to their container or the document window (for absolutely positioned popups). Defaults to <<.value no>> |
|
||||
|<<.attr clamp>> |Set to <<.value right>>, <<.value bottom>> or <<.value both>> to prevent a popup to overflow its container, see below |
|
||||
|<<.attr animate>> |Set to <<.value yes>> to animate opening and closing. Defaults to <<.value no>> |
|
||||
|<<.attr retain>> |Set to <<.value yes>> to force the content to be retained even when hidden. Defaults to <<.value no>> |
|
||||
|<<.attr updatePopupPosition>> |<<.from-version "5.1.23">>Set to <<.value yes>> to update the popup position when the state tiddler is updated. Defaults to <<.value no>> |
|
||||
|state |A TextReference containing the state |
|
||||
|stateTitle |A title containing the state, ''without'' TextReference. Gets preferred over the <<.attr state>> attribute |
|
||||
|stateField |A ''field name'' which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|
||||
|stateIndex |An ''index'' which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|
||||
|tag |Overrides the default [[HTML Tags]] (`<div>` in block mode or `<span>` in inline mode) |
|
||||
|type |The type of matching performed: ''match'', ''nomatch'', ''popup'', ''lt'', ''gt'', ''lteq'' or ''gteq'' |
|
||||
|text |The text to match when the type is ''match'', ''nomatch'', ''lt'', ''gt'', ''lteq'' or ''gteq'' |
|
||||
|class |An optional CSS class name to be assigned to the HTML element<br/>» Set to `tc-popup-keep` to make a popup "sticky", so it won't close when you click inside of it|
|
||||
|style |An optional CSS style attribute to be assigned to the HTML element |
|
||||
|position |The position used for the popup when the type is ''popup''. Can be ''left'', ''above'', ''aboveleft'', ''aboveright'', ''right'', ''belowleft'', ''belowright'' or ''below'' |
|
||||
|positionAllowNegative |Set to "yes" to prevent computed popup positions from being clamped to be above zero |
|
||||
|default |Default value to use when the state tiddler is missing |
|
||||
|animate |Set to "yes" to animate opening and closure (defaults to "no"; requires "retain" to be set to "yes") |
|
||||
|retain |Set to "yes" to force the content to be retained even when hidden (defaults to "no") |
|
||||
|updatePopupPosition|<<.from-version "5.1.23">>Set to "yes" to update the popup position when the state tiddler is updated (defaults to "no")|
|
||||
|
||||
<<.tip """<$macrocall $name=".from-version" version="5.1.18"/> <<.attr stateTitle>>, <<.attr stateField>> and <<.attr stateIndex>> attributes allow specifying Tiddler states directly, without interpreting them as [[TextReferences|TextReference]].
|
||||
<<.tip """<$macrocall $name=".from-version" version="5.1.18"/> <$macrocall $name=".attr" _="stateTitle"/>, <$macrocall $name=".attr" _="stateField"/> and <$macrocall $name=".attr" _="stateIndex"/> attributes allow specifying Tiddler states ''directly'', without interpreting them as [[TextReferences|TextReference]].
|
||||
This is useful for edge-cases where titles may contain characters that are used to denote Tiddler fields or indices (`!!`, `##`)""">>
|
||||
|
||||
<<.tip """Retaining the content when hidden can give poor performance since the hidden content requires refresh processing even though it is not displayed. On the other hand, the content can be revealed much more quickly. Note that setting `animate="yes"` will also require `retain="yes"`""">>
|
||||
|
||||
<<.tip """Set the <<.attr class>> attribute to <<.value tc-popup-keep>> to make a popup "sticky" so it will not close when you click inside of it""">>
|
||||
|
||||
!! <<.attr type>> Attribute
|
||||
|
||||
The <<.attr type>> of the widget determines the condition for the content being displayed:
|
||||
|
||||
* <<.value match>>: the content is displayed if the state tiddler matches the text attribute value
|
||||
* <<.value nomatch>>: the content is displayed if the state tiddler doesn't match the text attribute value
|
||||
* <<.value popup>>: the content is displayed as a popup as described in the PopupMechanism
|
||||
* <<.value lt>>: the content is displayed if the state tiddler contains an integer with a value ''less than'' the text attribute value
|
||||
* <<.value gt>>: the content is displayed if the state tiddler contains an integer with a value ''greater than'' the text attribute value
|
||||
* <<.value lteq>>: the content is displayed if the state tiddler contains an integer with a value ''less than or equal to'' the text attribute value
|
||||
* <<.value gteq>>: the content is displayed if the state tiddler contains an integer with a value ''greater than or equal to'' the text attribute value
|
||||
|
||||
!! Popup Clamping
|
||||
|
||||
Popups can be forced not to overflow their container (when relatively positioned) or the document window (when absolutely positioned). The popup's ''container'' is the nearest ancestor element with CSS positioning (<<.attr position>>: <<.value relative>>, <<.value absolute>>, <<.value fixed>>, or <<.value sticky>>).
|
||||
|
||||
Overflow to the left or top is prevented by setting <<.attr positionAllowNegative>> to <<.value no>> (the default). Clamping to the right and bottom is achieved by setting <<.attr clamp>> to <<.value right>>, <<.value bottom>> or <<.value both>>.
|
||||
|
||||
See [[Popup Clamping Example|RevealWidget (Popup Clamping Example)]]
|
||||
|
||||
|
||||
<<.tip """Refer to [[ButtonWidget]] and [[Coordinate Systems]] for information on relative and absolute positioning""">>
|
||||
<<.tip """Retaining the content when hidden can give poor performance since the hidden content requires refresh processing even though it is not displayed. On the other hand, the content can be revealed much more quickly. Note that setting ''animate="yes"'' will also require ''retain="yes"''""">>
|
||||
|
||||
! Examples
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
created: 20231218192649874
|
||||
modified: 20251212092210168
|
||||
tags: RevealWidget
|
||||
title: RevealWidget (Popup Clamping Example)
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
grid-template-rows: repeat(5, 1fr);
|
||||
width: 600px;
|
||||
height: 500px;
|
||||
overflow: hidden;
|
||||
background-color: #F8F8F8;
|
||||
position: relative;
|
||||
border: 1px solid #888;
|
||||
}
|
||||
.grid-item {
|
||||
justify-self: center;
|
||||
align-self: center;
|
||||
}
|
||||
.grid-popup .tc-drop-down {
|
||||
padding: 1em;
|
||||
min-width: 15em;
|
||||
}
|
||||
</style>
|
||||
|
||||
This example demonstrates the use of <<.attr positionAllowNegative>> and <<.attr clamp>> to clamp a popup inside its parent container.
|
||||
|
||||
<<.attr clamp>>=<$select tiddler="$:/temp/clamp-demo-active" field="text" default="none">
|
||||
<option value="none">none</option>
|
||||
<option value="right">right</option>
|
||||
<option value="bottom">bottom</option>
|
||||
<option value="both">both</option>
|
||||
</$select>
|
||||
|
||||
<$checkbox tiddler="$:/temp/clamp-demo-allow-negative" field="text" checked="yes" unchecked="no" default="no"> <<.attr positionAllowNegative>></$checkbox>
|
||||
|
||||
<<.attr position>>=<$select tiddler="$:/temp/clamp-demo-position" field="text" default="below">
|
||||
<option value="left">left</option>
|
||||
<option value="above">above</option>
|
||||
<option value="aboveleft">aboveleft</option>
|
||||
<option value="aboveright">aboveright</option>
|
||||
<option value="right">right</option>
|
||||
<option value="belowleft">belowleft</option>
|
||||
<option value="belowright">belowright</option>
|
||||
<option value="below">below</option>
|
||||
</$select>
|
||||
|
||||
<div class="container">
|
||||
<$list filter="[range[25]]">
|
||||
<div class="grid-item">
|
||||
<$button popup="$:/state/popup-clamping">Pop Me Up</$button>
|
||||
</div>
|
||||
</$list>
|
||||
<$reveal type="popup"
|
||||
position={{{ [{$:/temp/clamp-demo-position}else[below]] }}}
|
||||
state="$:/state/popup-clamping"
|
||||
class="grid-popup"
|
||||
clamp={{{ [{$:/temp/clamp-demo-active}else[none]] }}}
|
||||
positionAllowNegative={{{ [{$:/temp/clamp-demo-allow-negative}else[no]] }}}>
|
||||
<div class="tc-drop-down">
|
||||
|
||||
!! This is the popup
|
||||
And this is some text
|
||||
</div>
|
||||
</$reveal>
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@ This setting allows a custom alert message to be displayed when an attempt to st
|
||||
|
||||
! Prevent browser from evicting local storage
|
||||
|
||||
Permission for local storage persistence: ''{{$:/state/browser/storage/persisted}}''
|
||||
Permission for local storage persistence: ''{{$:/info/browser/storage/persisted}}''
|
||||
|
||||
The first time a tiddler is saved to local storage a request will be made to prevent automatic eviction of local storage for this site. This means the data will not be cleared unless the user manually clears it.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.synchronous = true;
|
||||
|
||||
var ENABLED_TITLE = "$:/config/BrowserStorage/Enabled",
|
||||
SAVE_FILTER_TITLE = "$:/config/BrowserStorage/SaveFilter",
|
||||
PERSISTED_STATE_TITLE = "$:/state/browser/storage/persisted";
|
||||
PERSISTED_STATE_TITLE = "$:/info/browser/storage/persisted";
|
||||
|
||||
var BrowserStorageUtil = require("$:/plugins/tiddlywiki/browser-storage/util.js").BrowserStorageUtil;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ exports.serialize = function (node) {
|
||||
if(node.orderedAttributes) {
|
||||
node.orderedAttributes.forEach(function (attribute) {
|
||||
if(attribute.name !== "$variable") {
|
||||
result += " " + $tw.utils.serializeAttribute(attribute,{assignmentSymbol:":"});
|
||||
result += " " + $tw.utils.serializeAttribute(attribute);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -62,14 +62,27 @@ exports.serializeAttribute = function(node,options) {
|
||||
}
|
||||
// If name is number, means it is a positional attribute and name is omitted
|
||||
var positional = parseInt(node.name) >= 0,
|
||||
// `=` in a widget and might be `:` in a macro
|
||||
assign = positional ? "" : (options.assignmentSymbol || "="),
|
||||
// Use the original assignment operator if available, otherwise default to '='
|
||||
assign = positional ? "" : (node.assignmentOperator || "="),
|
||||
attributeString = positional ? "" : node.name;
|
||||
if(node.type === "string") {
|
||||
if(node.value === "true") {
|
||||
return attributeString;
|
||||
}
|
||||
attributeString += assign + '"' + node.value + '"';
|
||||
// For macro parameters (using ':' separator), preserve unquoted values
|
||||
// For widget attributes (using '=' separator), always use quotes
|
||||
if(assign === ":" && !node.quoted) {
|
||||
attributeString += assign + node.value;
|
||||
} else if(assign === "") {
|
||||
// Positional parameter
|
||||
if(!node.quoted) {
|
||||
attributeString += node.value;
|
||||
} else {
|
||||
attributeString += '"' + node.value + '"';
|
||||
}
|
||||
} else {
|
||||
attributeString += assign + '"' + node.value + '"';
|
||||
}
|
||||
} else if(node.type === "filtered") {
|
||||
attributeString += assign + "{{{" + node.filter + "}}}";
|
||||
} else if(node.type === "indirect") {
|
||||
@@ -77,11 +90,36 @@ exports.serializeAttribute = function(node,options) {
|
||||
} else if(node.type === "substituted") {
|
||||
attributeString += assign + "`" + node.rawValue + "`";
|
||||
} else if(node.type === "macro") {
|
||||
if(node.value && typeof node.value === "object" && node.value.type === "macrocall") {
|
||||
var params = node.value.params.map(function(param) {
|
||||
return param.value;
|
||||
}).join(" ");
|
||||
attributeString += assign + "<<" + node.value.name + " " + params + ">>";
|
||||
if(node.value && typeof node.value === "object") {
|
||||
if(node.value.type === "transclude") {
|
||||
// Handle the transclude-based macro call structure
|
||||
var macroName = node.value.attributes && node.value.attributes["$variable"] ?
|
||||
node.value.attributes["$variable"].value : "";
|
||||
if(!macroName) {
|
||||
return null;
|
||||
}
|
||||
var params = [];
|
||||
if(node.value.orderedAttributes) {
|
||||
node.value.orderedAttributes.forEach(function(attr) {
|
||||
if(attr.name !== "$variable") {
|
||||
var paramStr = exports.serializeAttribute(attr);
|
||||
if(paramStr) {
|
||||
params.push(paramStr);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
attributeString += assign + "<<" + macroName + (params.length > 0 ? " " + params.join(" ") : "") + ">>";
|
||||
} else if(node.value.type === "macrocall") {
|
||||
// Handle the classical macrocall structure for backwards compatibility
|
||||
var params = node.value.params.map(function(param) {
|
||||
return param.value;
|
||||
}).join(" ");
|
||||
attributeString += assign + "<<" + node.value.name + " " + params + ">>";
|
||||
} else {
|
||||
// Unsupported macro structure
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// Unsupported macro structure
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user