1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-18 16:09:52 +00:00

Compare commits

..

54 Commits

Author SHA1 Message Date
Jeremy Ruston
e1625afab5 Docs updates 2026-01-31 13:10:02 +00:00
Jeremy Ruston
2e89771129 Merge branch 'master' into dynamic-macro-calls 2026-01-30 20:58:05 +00:00
Jeremy Ruston
a1ef2ef6d4 Merge branch 'tiddlywiki-com' 2026-01-29 14:27:59 +00:00
Saq Imtiaz
75edd9b488 Reverts change to getLocationHash utils method (#9622)
* fix: reverted change to getLocationHash utils method

* docs: update changenote
2026-01-26 16:03:50 +01:00
Jeremy Ruston
b6a91521d6 Docs updates 2026-01-25 21:31:53 +00:00
Jeremy Ruston
8ebf052e25 On reflection, new style values should not be allowed for anonymous parameters
Backwards compatibility
2026-01-25 20:27:01 +00:00
Jeremy Ruston
a29ae908e2 Only allow new style parameter values if the separator is an equals sign 2026-01-25 20:21:39 +00:00
Jeremy Ruston
ff352d63da Allow single closing square brackets within double square brackets quoted strings 2026-01-25 19:56:53 +00:00
Jeremy Ruston
4729e15925 Add change note 2026-01-25 19:35:23 +00:00
Jeremy Ruston
7ec985f8e6 Remove debug logging 2026-01-25 19:26:42 +00:00
Jeremy Ruston
cadddc13dc Genuflecting to the linter 2026-01-25 19:23:44 +00:00
Jeremy Ruston
a2f38ef51d Merge branch 'master' into dynamic-macro-calls 2026-01-25 19:19:15 +00:00
Mario Pietsch
cde9c931c8 Select widget handle default parameter refresh (#9617)
* select widget handle default parameter refresh

* Add change note
2026-01-25 19:58:52 +01:00
Saq Imtiaz
d07fe25cdb feat: extend fakedom implementation (#9616)
* feat: extend fakedom implementation

* docs: updated changenote
2026-01-25 19:05:46 +01:00
KiXaM_刻む
a40ce29451 Add an option to enable CORS (#9277)
* Add an option to disable CORS

* change 'disable' with 'enable' CORS, because that is what this option actually does

* add a change note

* typo
2026-01-25 17:04:16 +01:00
buggyj
75647eb623 Fixes #8092 SelectWidget does not work with multiple options organise… (#8093)
* Fixes #8092 SelectWidget does not work with multiple options organised into group

* Consolidate variables

* Apply suggestion from @saqimtiaz

* Update core/modules/widgets/select.js

Co-authored-by: Mario Pietsch <pmariojo@gmail.com>

* added release note

* chore: lint fixes

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
Co-authored-by: Mario Pietsch <pmariojo@gmail.com>
2026-01-25 17:02:18 +01:00
Mario Pietsch
70b4557738 [DOCS] Add link to "TiddlyWiki Archive" tiddler to the TiddlyWiki Releases info (#9613) 2026-01-25 16:59:54 +01:00
Mario Pietsch
efe58e41bc [DOCS] Fix some typos in "days Operator (Examples)" (#9479)
* [DOCS] Fix some typos in "days Operator (Examples)"

* Remove created and modified fields from days.tid

Remove created and modified fields from days.tid
2026-01-21 09:09:14 +01:00
Saq Imtiaz
eb3a80968e docs: changenotes for previously merged PRs (#9599)
* docs: changenotes for previously merged PRs

* fix: added text field for changenotes
2026-01-21 09:08:50 +01:00
Mario Pietsch
62ae4b24bc allow space after const {}. Set keyword spacing to warning (#9589) 2026-01-20 22:03:43 +01:00
yaisog
ded76aa84f Fixes Ctrl-Enter not working in EditTemplate tag name input (#9600)
* Assign save-tiddler-actions to inputAcceptVariantActions

* Add changenote
2026-01-20 20:22:42 +01:00
Mario Pietsch
79e3d14698 [DOCS] Make TaskManagementExamples more "hackable" (#9482)
* [DOCS] Make TaskManagementExamples more "hackable"

* Update modified date in TaskManagementExample.tid

* Fix modified date in TaskManagementExampleDraggable
2026-01-20 13:23:17 +01:00
superuser-does
763d717a13 Improvements to DateFormat tiddler (#9583) 2026-01-20 13:18:24 +01:00
XLBilly
e42ed6808e Split escapecss into two platforms (#9475)
* Split escapecss into to platforms

This will reduce core size slightly

* Update change note
2026-01-20 12:13:48 +01:00
yaisog
844564180f Fix LetWidget to always set all staged variables on first render (#9494)
* Always set all staged variables on first render

* Add changenote
2026-01-20 10:24:56 +00:00
Saq Imtiaz
a670de0e95 Fixes regressions in list-tagged-draggable (#9596)
* Fix regressions in list-tagged-draggable

* Remove trailing newline from list.tid
2026-01-20 10:01:02 +01:00
Bram Chen
faee49ee01 Update chinese language files (#9576)
* Update chinese language files
* add chinese translations for alert aria message

* Update chinese language files
* update related change note
2026-01-20 07:33:05 +01:00
yaisog
dd20be49f0 Make impact note for #9337 less verbose / repetitive (#9481)
* Make impact note less verbose / repetitive for #9337

* Correct some fields
2026-01-20 07:16:21 +01:00
Simon Huber
a27f74bbdc Fixes bug in sidebar tab Open to allow disabling drag and drop (#9504)
the variable is called `tv-enable-drag-and-drop` - not `tv-allow-drag-and-drop`
2026-01-20 07:06:29 +01:00
Jeremy Ruston
ae4e99951a Revert #9554 Refactor stylesheets in single <style> tags
These changes break the palette switcher
2026-01-18 11:40:10 +00:00
Mario Pietsch
be84dee26b Allow unused variables in function headers and caught exceptions (#9588) 2026-01-17 17:51:51 +00:00
XLBilly
00e17874f0 Add stylesheet wiki information (#9565)
* Add stylesheet wiki information

* Use 2 spaces

* Update change note

* Use ∈ symbol instead
I think this one is less confusing than the previous one
2026-01-17 15:00:32 +00:00
XLBilly
9041f099a3 Refactor stylesheets in single <style> tags (#9554)
* Create RootStylesheet.tid

* put stylesheets into single <style> tags

* viewHandler should not be a widget

* format RootStylesheet

* add ROOT_STYLESHEET_TITLE constant

* use let widget in RootStylesheet

* use view widget from #8135 for testing

* reformat RootStylesheet

* update view widget

* update view widget

* update view widget

* update view widget

* update view widget

* update view widget

* trying to fix the date parsing

* refactor view widget with more extensible architecture

* remove performance instrumentation

* hardcode reset and base stylesheets

* adopt ES2017 syntax for view widget

* don't hardcode vanilla/base

* remove unused constructors

* remove unused variable

* make refresh method static

* trying to fix missingThis

* add changenote

* revert change in vanilla/base

* Revert changes to the view widget

* Refactor RootStylesheet.tid
* Use transclude widget instead of view widget
* Remove hardcoded noramlize.css

* Add comment for debugging

* Migrate some templates to use RootStylesheet

* Remove PAGE_STYLESHEET_TITLE
Since it is no longer used in render.js

* Update change note

---------

Co-authored-by: Simon Huber <huber.simon@protonmail.com>
2026-01-17 14:59:10 +00:00
yaisog
3ba31be2a8 Add the words and lines modes to $diff-text (#9551)
* Initial commit

* Add line ending configuration for consistent tests

* Initial commit

* Correctly consider editcost parameter

* Move diffPartsToChars() to $tw.utils

* Remove superfluous file

* Correct "efficiency" parameter naming in the documentation

The parameter was incorrectly referred to as "efficent" in several places.

* Update diffPartsToChars to ES2017 style

* Consolidate let/const declarations
2026-01-17 14:57:52 +00:00
XLBilly
99d8afd515 Bump markdown-it to latest version (#9513)
* Bump markdown-it to newest version

* Update change note
2026-01-17 14:56:16 +00:00
Jeremy Ruston
2ab5f26644 Merge branch 'tiddlywiki-com' 2026-01-16 17:36:54 +00:00
Mario Pietsch
419fe68ee2 [Docs] Improve tag-pill documentation and examples (#9580)
* [Docs] Improve tag-pill documentation and examples

* Apply suggestion from @saqimtiaz

---------

Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
2026-01-14 14:04:34 +01:00
XLBilly
0e765bdbdb Make alert aria message translatable (#9575)
* Make alerts aria message translatable

* Update change notes

* Update change note
2026-01-12 10:21:35 +01:00
Jeremy Ruston
855d8a9638 Fix images loaded from _canonical_uri tiddlers do not have loading and error classes assigned (#9570)
* Fix images loaded from _canonical_uri tiddlers do not have loading and error classes assigned

* Create changenote

* Joyously fix eslint error
2026-01-10 14:50:31 +00:00
Jeremy Ruston
afcf108d29 Add changenote 2026-01-10 14:42:58 +00:00
Jeremy Ruston
8f9acc0ca2 Fix missing file extension 2026-01-10 14:35:26 +00:00
Jeremy Ruston
54ebf60a05 Merge branch 'master' into dynamic-macro-calls 2025-12-18 21:09:07 +00:00
Jeremy Ruston
5d72fb0608 Minor docs update 2025-12-18 21:08:54 +00:00
Jeremy Ruston
30e6092819 Fix unneeded diff 2025-11-24 11:11:33 +00:00
lin onetwo
4305a0bb92 Fix/dynamic macro calls test (#9459)
* Revert "Temporarily disable a broken serializer test"

This reverts commit b3144300ee.

* restore synamic parameter parse result

* lint

* lint

* remove duplicate

* Update core/modules/parsers/parseutils.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update editions/test/tiddlers/tests/data/serialize/DynamicWidgetAttribute.tid

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update editions/test/tiddlers/tests/data/serialize/DynamicWidgetAttribute.tid

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: mixed qouted and unquoted

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 11:10:42 +00:00
Jeremy Ruston
b3144300ee Temporarily disable a broken serializer test 2025-11-23 21:04:04 +00:00
Jeremy Ruston
205e8cf9c9 Fix test 2025-11-23 21:03:32 +00:00
Jeremy Ruston
ad4c1ca5a1 Merge branch 'master' into dynamic-macro-calls 2025-11-23 20:59:41 +00:00
Jeremy Ruston
5136e33f07 Tweak examples 2025-05-15 15:09:05 +01:00
Jeremy Ruston
744f6e7a3b Add some examples 2025-05-12 17:43:45 +01:00
Jeremy Ruston
1ded43f6ea Test for attribute macros 2025-05-12 17:32:30 +01:00
Jeremy Ruston
48e6863a89 Parse attribute macros with the new parser
This fixes the tests
2025-05-12 17:16:08 +01:00
Jeremy Ruston
f5d5a23aff Test for standalone macro calls with dynamic parameters 2025-05-12 14:26:21 +01:00
Jeremy Ruston
2d6b6b5011 Initial commit
The idea is to extend the macro call syntax to accept dynamic parameter values (ie thing:{{more}} etc). Eventually, this will work in all the contexts in which the double angle bracket syntax is valid.

This initial commit gets the tests passing, but doesn't yet activate the new functionality.
2025-05-12 14:03:29 +01:00
90 changed files with 1511 additions and 606 deletions

View File

@@ -316,8 +316,25 @@ $tw.utils.htmlDecode = function(s) {
return s.toString().replace(/&lt;/mg,"<").replace(/&nbsp;/mg,"\xA0").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
};
/** @deprecated Use window.location.hash instead. */
$tw.utils.getLocationHash = () => window.location.hash;
/*
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
*/
$tw.utils.getLocationHash = function() {
const href = window.location.href,
idx = href.indexOf("#");
if(idx === -1) {
return "#";
}
const afterHash = href.substring(idx + 1);
if(afterHash.startsWith("#") || afterHash.startsWith("%23")) {
// Special case: ignore location hash if it itself starts with a #
return "#";
}
return href.substring(idx);
};
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
$tw.utils.pad = function(value,length = 2) {

View File

@@ -42,6 +42,8 @@ function Server(options) {
}
// Setup the default required plugins
this.requiredPlugins = this.get("required-plugins").split(',');
// Initialise CORS
this.corsEnable = this.get("cors-enable") === "yes";
// Initialise CSRF
this.csrfDisable = this.get("csrf-disable") === "yes";
// Initialize Gzip compression
@@ -261,6 +263,13 @@ Server.prototype.requestHandler = function(request,response,options) {
state.urlInfo = url.parse(request.url);
state.queryParameters = querystring.parse(state.urlInfo.query);
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
// Enable CORS
if(this.corsEnable) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Expose-Headers", "*");
}
state.sendResponse = sendResponse.bind(self,request,response);
// Get the principals authorized to access this resource
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
@@ -285,6 +294,12 @@ Server.prototype.requestHandler = function(request,response,options) {
response.end();
return;
}
// Reply to OPTIONS
if(this.corsEnable && request.method === "OPTIONS") {
response.writeHead(204);
response.end();
return;
}
// Find the route that matches this path
var route = self.findMatchingRoute(request,state);
// Optionally output debug info

View File

@@ -0,0 +1,95 @@
/*\
title: $:/core-server/modules/utils/escapecss.js
type: application/javascript
module-type: utils-node
Provides CSS.escape() functionality.
\*/
"use strict";
exports.escapeCSS = (function() {
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
/* eslint-disable */
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
return function(value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};
/* eslint-enable */
})();

View File

@@ -1,5 +1,6 @@
title: $:/language/
Alerts: Alerts
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
BinaryWarning/Prompt: This tiddler contains binary data
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.

View File

@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
operand = (operator.operand || ""),
fnCalc;
if(suffix === "prefix") {
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];};
} else if(suffix === "suffix") {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];};
} else {
if(operand === "") {
fnCalc = function(a) {return [$tw.utils.trim(a)];}
fnCalc = function(a) {return [$tw.utils.trim(a)];};
} else {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];};
}
}
source(function(tiddler,title) {
@@ -80,9 +80,9 @@ exports.levenshtein = makeStringBinaryOperator(
}
);
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode) {
var a = diffPartsToChars(text1,text2,mode);
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1;
var lineText2 = a.chars2;
var lineArray = a.lineArray;
@@ -91,56 +91,6 @@ function diffLineWordMode(text1,text2,mode) {
return diffs;
}
function diffPartsToChars(text1,text2,mode) {
var lineArray = [];
var lineHash = {};
lineArray[0] = "";
function diff_linesToPartsMunge_(text,mode) {
var chars = "";
var lineStart = 0;
var lineEnd = -1;
var lineArrayLength = lineArray.length,
regexpResult;
var searchRegexp = /\W+/g;
while(lineEnd < text.length - 1) {
if(mode === "words") {
regexpResult = searchRegexp.exec(text);
lineEnd = searchRegexp.lastIndex;
if(regexpResult === null) {
lineEnd = text.length;
}
lineEnd = --lineEnd;
} else {
lineEnd = text.indexOf("\n", lineStart);
if(lineEnd == -1) {
lineEnd = text.length - 1;
}
}
var line = text.substring(lineStart, lineEnd + 1);
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
chars += String.fromCharCode(lineHash[line]);
} else {
if(lineArrayLength == maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
var maxLines = 40000;
var chars1 = diff_linesToPartsMunge_(text1,mode);
maxLines = 65535;
var chars2 = diff_linesToPartsMunge_(text2,mode);
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
};
exports.makepatches = function(source,operator,options) {
var suffix = operator.suffix || "",
result = [];
@@ -275,7 +225,7 @@ exports.pad = function(source,operator,options) {
}
});
return results;
}
};
exports.charcode = function(source,operator,options) {
var chars = [];

View File

@@ -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 {
@@ -173,7 +174,7 @@ exports.parseMacroParameter = function(source,pos) {
start: pos
};
// Define our regexp
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter
@@ -206,28 +207,152 @@ 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;
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) {
return null;
}
pos = token.end;
// Get the variable name for the macro
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
if(!token) {
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) === ">") ) {
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) {
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),
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
// 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;
isNewStyleSeparator = (node.assignmentOperator === "=");
}
// 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 {
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue && isNewStyleSeparator) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue && isNewStyleSeparator) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// 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];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation && isNewStyleSeparator) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue && isNewStyleSeparator) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
}
}
}
}
}
}
// Bail if we don't have a value
if(!node.type) {
return null;
}
// Update the end position
node.end = pos;
return node;
};
@@ -296,7 +421,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 +479,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 +500,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";
}

View File

@@ -37,7 +37,7 @@ exports.parse = function() {
var paramString = this.match[2],
params = [];
if(paramString !== "") {
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))?/mg,
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|([^"'\s]+)))?/mg,
paramMatch = reParam.exec(paramString);
while(paramMatch) {
// Save the parameter details

View File

@@ -1,7 +1,7 @@
/*\
title: $:/core/modules/utils/escapecss.js
type: application/javascript
module-type: utils
module-type: utils-browser
Provides CSS.escape() functionality.
@@ -9,92 +9,6 @@ Provides CSS.escape() functionality.
"use strict";
// TODO -- resolve this construction
exports.escapeCSS = (function() {
// use browser's native CSS.escape() function if available
if ($tw.browser && window.CSS && window.CSS.escape) {
return window.CSS.escape;
}
// otherwise, a utility method is provided
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
return function(value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};
return window.CSS.escape;
})();

View File

@@ -37,6 +37,7 @@ Object.defineProperty(TW_Node.prototype, 'TEXT_NODE', {
var TW_TextNode = function(text) {
bumpSequenceNumber(this);
this.textContent = text + "";
this.children = [];
};
Object.setPrototypeOf(TW_TextNode.prototype,TW_Node.prototype);

View File

@@ -55,7 +55,7 @@ Return the dflt (default) parameter if str is not a base-10 number.
exports.getInt = function(str,deflt) {
var i = parseInt(str,10);
return isNaN(i) ? deflt : i;
}
};
/*
Repeatedly replaces a substring within a string. Like String.prototype.replace, but without any of the default special handling of $ sequences in the replace string
@@ -69,12 +69,12 @@ exports.replaceString = function(text,search,replace) {
exports.trimPrefix = function(str,unwanted) {
if(typeof str === "string" && typeof unwanted === "string") {
if(unwanted === "") {
return str.replace(/^\s\s*/, '');
return str.replace(/^\s\s*/, "");
} else {
// Safely regexp-escape the unwanted text
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
var regex = new RegExp('^(' + unwanted + ')+');
return str.replace(regex, '');
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
var regex = new RegExp("^(" + unwanted + ")+");
return str.replace(regex, "");
}
} else {
return str;
@@ -84,12 +84,12 @@ exports.trimPrefix = function(str,unwanted) {
exports.trimSuffix = function(str,unwanted) {
if(typeof str === "string" && typeof unwanted === "string") {
if(unwanted === "") {
return str.replace(/\s\s*$/, '');
return str.replace(/\s\s*$/, "");
} else {
// Safely regexp-escape the unwanted text
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
var regex = new RegExp('(' + unwanted + ')+$');
return str.replace(regex, '');
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
var regex = new RegExp("(" + unwanted + ")+$");
return str.replace(regex, "");
}
} else {
return str;
@@ -101,14 +101,14 @@ Convert a string to sentence case (ie capitalise first letter)
*/
exports.toSentenceCase = function(str) {
return (str || "").replace(/^\S/, function(c) {return c.toUpperCase();});
}
};
/*
Convert a string to title case (ie capitalise each initial letter)
*/
exports.toTitleCase = function(str) {
return (str || "").replace(/(^|\s)\S/g, function(c) {return c.toUpperCase();});
}
};
/*
Find the line break preceding a given position in a string
@@ -358,8 +358,8 @@ exports.formatDateString = function(date,template) {
}],
[/^TZD/, function() {
var tz = date.getTimezoneOffset(),
atz = Math.abs(tz);
return (tz < 0 ? '+' : '-') + $tw.utils.pad(Math.floor(atz / 60)) + ':' + $tw.utils.pad(atz % 60);
atz = Math.abs(tz);
return (tz < 0 ? "+" : "-") + $tw.utils.pad(Math.floor(atz / 60)) + ":" + $tw.utils.pad(atz % 60);
}],
[/^wYY/, function() {
return $tw.utils.pad($tw.utils.getYearForWeekNo(date) - 2000);
@@ -568,9 +568,9 @@ exports.unescapeLineBreaks = function(s) {
exports.escape = function(ch) {
var charCode = ch.charCodeAt(0);
if(charCode <= 0xFF) {
return '\\x' + $tw.utils.pad(charCode.toString(16).toUpperCase());
return "\\x" + $tw.utils.pad(charCode.toString(16).toUpperCase());
} else {
return '\\u' + $tw.utils.pad(charCode.toString(16).toUpperCase(),4);
return "\\u" + $tw.utils.pad(charCode.toString(16).toUpperCase(),4);
}
};
@@ -587,11 +587,11 @@ exports.stringify = function(s, rawUnicode) {
*/
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
return (s || "")
.replace(/\\/g, '\\\\') // backslash
.replace(/\\/g, "\\\\") // backslash
.replace(/"/g, '\\"') // double quote character
.replace(/'/g, "\\'") // single quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\n/g, '\\n') // line feed
.replace(/\r/g, "\\r") // carriage return
.replace(/\n/g, "\\n") // line feed
.replace(regex, exports.escape); // non-ASCII characters
};
@@ -601,15 +601,15 @@ exports.jsonStringify = function(s, rawUnicode) {
// See http://www.json.org/
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
return (s || "")
.replace(/\\/g, '\\\\') // backslash
.replace(/\\/g, "\\\\") // backslash
.replace(/"/g, '\\"') // double quote character
.replace(/\r/g, '\\r') // carriage return
.replace(/\n/g, '\\n') // line feed
.replace(/\x08/g, '\\b') // backspace
.replace(/\x0c/g, '\\f') // formfeed
.replace(/\t/g, '\\t') // tab
.replace(/\r/g, "\\r") // carriage return
.replace(/\n/g, "\\n") // line feed
.replace(/\x08/g, "\\b") // backspace
.replace(/\x0c/g, "\\f") // formfeed
.replace(/\t/g, "\\t") // tab
.replace(regex,function(s) {
return '\\u' + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
return "\\u" + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
}); // non-ASCII characters
};
@@ -617,7 +617,7 @@ exports.jsonStringify = function(s, rawUnicode) {
Escape the RegExp special characters with a preceding backslash
*/
exports.escapeRegExp = function(s) {
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&');
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, "\\$&");
};
/*
@@ -700,7 +700,7 @@ exports.parseTextReference = function(textRef) {
}
} else {
// If we couldn't parse it
result.title = textRef
result.title = textRef;
}
return result;
};
@@ -759,9 +759,9 @@ Cryptographic hash function as used by sha256 filter operator
options.length .. number of characters returned defaults to 64
*/
exports.sha256 = function(str, options) {
options = options || {}
options = options || {};
return $tw.sjcl.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
}
};
/*
Decode a base64 string
@@ -914,3 +914,56 @@ exports.makeCompareFunction = function(type,options) {
};
return (types[type] || types[options.defaultType] || types.number);
};
/*
Split text into parts (lines or words) for diff operations
Adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
*/
exports.diffPartsToChars = function(text1,text2,mode) {
const lineArray = [""],
lineHash = Object.create(null);
function diff_linesToPartsMunge_(text,mode) {
let chars = "",
lineStart = 0,
lineEnd = -1,
lineArrayLength = lineArray.length,
regexpResult;
const searchRegexp = /\W+/g;
while(lineEnd < text.length - 1) {
if(mode === "words") {
regexpResult = searchRegexp.exec(text);
lineEnd = searchRegexp.lastIndex;
if(regexpResult === null) {
lineEnd = text.length;
}
lineEnd = --lineEnd;
} else {
lineEnd = text.indexOf("\n", lineStart);
if(lineEnd === -1) {
lineEnd = text.length - 1;
}
}
let line = text.substring(lineStart, lineEnd + 1);
if(line in lineHash) {
chars += String.fromCharCode(lineHash[line]);
} else {
if(lineArrayLength === maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
let maxLines = 40000;
const chars1 = diff_linesToPartsMunge_(text1,mode);
maxLines = 65535;
const chars2 = diff_linesToPartsMunge_(text2,mode);
return {chars1, chars2, lineArray};
};

View File

@@ -36,7 +36,13 @@ DiffTextWidget.prototype.render = function(parent,nextSibling) {
this.execute();
// Create the diff object
const editCost = $tw.utils.parseNumber(this.getAttribute("editcost","4"));
const diffs = dmp.diffMain(this.getAttribute("source",""),this.getAttribute("dest",""),{diffEditCost: editCost});
const mode = this.getAttribute("mode") || "chars";
let diffs;
if(mode === "lines" || mode === "words") {
diffs = diffLineWordMode(this.getAttribute("source",""),this.getAttribute("dest",""),mode,editCost);
} else {
diffs = dmp.diffMain(this.getAttribute("source",""),this.getAttribute("dest",""),{diffEditCost: editCost});
}
// Apply required cleanup
switch(this.getAttribute("cleanup","semantic")) {
case "none":
@@ -132,7 +138,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/
DiffTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.editcost) {
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.mode || changedAttributes.editcost) {
this.refreshSelf();
return true;
} else {
@@ -140,4 +146,15 @@ DiffTextWidget.prototype.refresh = function(changedTiddlers) {
}
};
// This function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode,editCost) {
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1;
var lineText2 = a.chars2;
var lineArray = a.lineArray;
var diffs = dmp.diffMain(lineText1,lineText2,{diffEditCost: editCost});
dmp.diffCharsToLines(diffs,lineArray);
return diffs;
}
exports["diff-text"] = DiffTextWidget;

View File

@@ -7,7 +7,6 @@ This widget allows defining multiple variables at once, while allowing
the later variables to depend upon the earlier ones.
```
\define helloworld() Hello world!
<$let currentTiddler="target" value={{!!value}} currentTiddler="different">
{{!!value}} will be different from <<value>>
</$let>
@@ -56,7 +55,7 @@ LetWidget.prototype.computeAttributes = function() {
});
// Run through again, setting variables and looking for differences
$tw.utils.each(this.currentValueFor,function(value,name) {
if(!$tw.utils.isArrayEqual(self.attributes[name],value)) {
if(self.attributes[name] === undefined || !$tw.utils.isArrayEqual(self.attributes[name],value)) {
self.attributes[name] = value;
self.setVariable(name,value);
changedAttributes[name] = true;
@@ -68,7 +67,7 @@ LetWidget.prototype.computeAttributes = function() {
LetWidget.prototype.getVariableInfo = function(name,options) {
// Special handling: If this variable exists in this very $let, we can
// use it, but only if it's been staged.
if ($tw.utils.hop(this.currentValueFor,name)) {
if($tw.utils.hop(this.currentValueFor,name)) {
var value = this.currentValueFor[name];
return {
text: value[0] || "",

View File

@@ -82,8 +82,8 @@ SelectWidget.prototype.handleChangeEvent = function(event) {
if(this.selectMultiple == false) {
var value = this.getSelectDomNode().value;
} else {
var value = this.getSelectValues()
value = $tw.utils.stringifyList(value);
var value = this.getSelectValues();
value = $tw.utils.stringifyList(value);
}
this.wiki.setText(this.selectTitle,this.selectField,this.selectIndex,value);
// Trigger actions
@@ -118,12 +118,21 @@ SelectWidget.prototype.setSelectValue = function() {
}
}
// Assign it to the select element if it's different than the current value
if (this.selectMultiple) {
if(this.selectMultiple) {
value = value === undefined ? "" : value;
var select = this.getSelectDomNode();
var values = Array.isArray(value) ? value : $tw.utils.parseStringArray(value);
var child,
values = Array.isArray(value) ? value : $tw.utils.parseStringArray(value);
for(var i=0; i < select.children.length; i++){
select.children[i].selected = values.indexOf(select.children[i].value) !== -1
child=select.children[i];
if(child.children.length === 0){
child.selected = values.indexOf(child.value) !== -1;
} else {
// grouped options
for(var y=0; y < child.children.length; y++){
child.children[y].selected = values.indexOf(child.children[y].value) !== -1;
}
}
}
} else {
var domNode = this.getSelectDomNode();
@@ -147,14 +156,14 @@ SelectWidget.prototype.getSelectValues = function() {
select = this.getSelectDomNode();
result = [];
options = select && select.options;
for (var i=0; i<options.length; i++) {
for(var i=0; i<options.length; i++) {
opt = options[i];
if (opt.selected) {
if(opt.selected) {
result.push(opt.value || opt.text);
}
}
return result;
}
};
/*
Compute the internal state of the widget
@@ -183,7 +192,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
SelectWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// If we're using a different tiddler/field/index then completely refresh ourselves
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip || changedAttributes.tabindex || changedAttributes.disabled) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.tooltip || changedAttributes.default || changedAttributes.tabindex || changedAttributes.disabled) {
this.refreshSelf();
return true;
} else {

View File

@@ -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 {

View File

@@ -1,7 +1,7 @@
title: $:/core/ui/PageTemplate/alerts
tags: $:/tags/PageTemplate
<div class="tc-alerts" role="region" aria-label="Alerts">
<div class="tc-alerts" role="region" aria-label={{$:/language/Alerts}}>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Alert]!is[draft]]" template="$:/core/ui/AlertTemplate" storyview="pop"/>

View File

@@ -15,7 +15,7 @@ caption: {{$:/language/SideBar/Open/Caption}}
\define droppable-item(button)
\whitespace trim
<$droppable actions=<<drop-actions>> enable=<<tv-allow-drag-and-drop>> tag="div">
<$droppable actions=<<drop-actions>> enable=<<tv-enable-drag-and-drop>> tag="div">
<<placeholder>>
<div>
$button$

View File

@@ -41,6 +41,8 @@ Drag this link to copy this tool to another wiki
</$wikify>
\end capture-item-wikified
\function get.shadow.source() [shadowsource[]]
\procedure capture-wiki-info(tempWikiInfo)
<$transclude $variable="capture-item-wikified" label="TiddlyWiki Version" value="<<version>>"/>
<$transclude $variable="capture-item" label="Current palette" value={{$:/palette}}/>
@@ -64,6 +66,7 @@ Drag this link to copy this tool to another wiki
<$transclude $variable="capture-item" label="Keyboard shortcuts that have been customised" value={{{ [all[tiddlers]prefix[$:/config/shortcuts]] +[join[,]] }}}/>
<$transclude $variable="capture-item" label="Disabled plugins" value={{{ [all[tiddlers]prefix[$:/config/Plugins/Disabled/]] :filter[{!!text}match[yes]] :map[<currentTiddler>removeprefix[$:/config/Plugins/Disabled/]] +[join[,]] }}}/>
<$transclude $variable="capture-item" label="Plugins" value={{{ [has[plugin-type]sort[]] :filter[<currentTiddler>addprefix[$:/config/Plugins/Disabled/]get[text]else[no]!match[yes]] :map[{!!version}addprefix[ - ]addprefix<currentTiddler>] +[addprefix[ ]addprefix<crlf>join[]] }}}/>
<$transclude $variable="capture-item" label="Stylesheets" value={{{ [all[shadows+tiddlers]tag[$:/tags/Stylesheet]!is[draft]] :map[is[shadow]addsuffix[ ∈ ]addsuffix<get.shadow.source>else<currentTiddler>] +[addprefix[ ]addprefix<crlf>join[]] }}}/>
\end capture-wiki-info
\procedure template-header()

View File

@@ -92,7 +92,7 @@ tags: $:/tags/Macro
</$set>
\end
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"",displayField:"caption")
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"",displayField:"title")
\whitespace trim
<span class="tc-tagged-draggable-list">
<$set name="tag" value=<<__tag__>>>
@@ -115,7 +115,6 @@ tags: $:/tags/Macro
<$view field="title"/>
</$transclude>
</$let>
<$view field="title"/>
</$link>
</$transclude>
</$genesis>

View File

@@ -21,7 +21,7 @@ second-search-filter: [subfilter<tagListFilter>is[system]search:title<userInput>
<!-- clean up temporary tiddlers, so the next "pick" starts with a clean input -->
<!-- This could probably be optimized / removed if we would use different temp-tiddlers
(future improvement because keeping track is comlex for humans)
(future improvement because keeping track is complex for humans)
-->
\procedure delete-tag-state-tiddlers()
<$action-deletetiddler $filter="[<newTagNameTiddler>] [<storeTitle>] [<tagSelectionState>]"/>
@@ -111,6 +111,7 @@ The second ESC tries to close the "draft tiddler"
refreshTitle=<<refreshTitle>>
selectionStateTitle=<<tagSelectionState>>
inputAcceptActions=<<add-tag-actions>>
inputAcceptVariantActions=<<save-tiddler-actions>>
inputCancelActions=<<clear-tags-actions>>
tag="input"
placeholder={{$:/language/EditTemplate/Tags/Add/Placeholder}}

View File

@@ -1,11 +1,13 @@
created: 20150220191009000
modified: 20150602092431500
title: $:/editions/tw5.com/railroad/macro-parameter-value
title: $:/editions/tw5.com/railroad/call-parameter-value
type: text/vnd.tiddlywiki.railroad
( '"""' [:{/'tout sauf """'/}] '"""'
| '"' [:{/'tout sauf "'/}] '"'
| "'" [:{/"tout sauf '"/}] "'"
| "[[" [:{/"tout sauf ]"/}] "]]"
| "`" [:{/"tout sauf `"/}] "`"
| "```" [:{/"tout sauf ```"/}] "```"
| {/"""tout sauf ' " ou espacevierge"""/}
)

View File

@@ -25,4 +25,4 @@ The <<.place param-nom>> is a sequence of letters (`A`--`Z`, `a`--`z`), digits (
The <<.place valeur>> is specified as follows<<dp>>
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<$railroad text={{$:/editions/tw5.com/railroad/call-parameter-value}}/>

View File

@@ -33,7 +33,7 @@ parametre.nom [: [:espace] ":" [:espace] defaut ]
La valeur par <<.place défaut>> d'un paramètre est spécifiée comme suit<<:>>
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<$railroad text={{$:/editions/tw5.com/railroad/call-parameter-value}}/>
La définition de la <<.place suite>> se fait comme suit<<:>>

View File

@@ -0,0 +1,26 @@
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>>/>
+
title: ExpectedResult
<p>It is red
-
It is ba
-
It is param
</p>

View File

@@ -0,0 +1,23 @@
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={{{ [[b]addprefix[a]] }}}>>
<<mamacro one>>
+
title: ExpectedResult
<p>It is red and green or red 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>

View File

@@ -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)$`>>

View File

@@ -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">>/>

View File

@@ -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}}>>/>

View File

@@ -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>>

View File

@@ -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">>.

View File

@@ -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
}
);
});

View File

@@ -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"}]
);

View File

@@ -1,7 +1,9 @@
created: 20211117003509226
modified: 20251119135921343
modified: 20260102135713260
tags: sampletag1 sampletag2 [[Widget Examples]]
title: SampleTiddlerFirst
type: text/vnd.tiddlywiki
This is a test tiddler called SampleTidlerFirst.
This is a test tiddler called SampleTidlerFirst.
It is used in [[DiffTextWidget]].
You can modify its content.

View File

@@ -1,6 +1,8 @@
created: 20211117003511221
modified: 20211117003724108
modified: 20260102135739735
tags: sampletag1 sampletag2 [[Widget Examples]]
title: SampleTiddlerSecond
This test tiddler is called SampleTiddlerSecond.
This test tiddler is called SampleTiddlerSecond.
It is used in [[DiffTextWidget]].
You can edit its content.

View File

@@ -4,22 +4,22 @@ tags: Learning
title: TaskManagementExample
type: text/vnd.tiddlywiki
TiddlyWiki5 can be used as a simple task management system without further customisation. The idea is that tasks be tagged `task`, with those that are completed also tagged `done`. In this way it is straightforward to generate task lists.
TiddlyWiki5 can be used as a simple task management system without further customisation.<br>The idea is that tasks be tagged `task`, with those that are completed also tagged `done`. In this way it is straightforward to generate task lists.
<<.tip """There is [[an enhanced version of this demo|TaskManagementExample (Draggable)]] that adds the ability to drag and drop the tasks to re-order them.""">>
! Outstanding tasks
<$list filter="[!has[draft.of]tag[task]!tag[done]sort[created]]">
<$checkbox tag="done"> <$link/></$checkbox>
<$macrocall $name='wikitext-example-without-html'
src="""<$list filter="[!has[draft.of]tag[task]!tag[done]sort[created]]">
<$checkbox tag="done"> <$link/></$checkbox><br>
</$list>
"""/>
! Completed tasks
<$list filter="[!has[draft.of]tag[task]tag[done]sort[created]]">
<$checkbox tag="done"> ~~<$link/>~~</$checkbox>
<$macrocall $name='wikitext-example-without-html'
src="""<$list filter="[!has[draft.of]tag[task]tag[done]sort[created]]">
<$checkbox tag="done"> ~~<$link/>~~</$checkbox><br>
</$list>
"""/>

View File

@@ -4,20 +4,24 @@ tags: Learning
title: TaskManagementExample (Draggable)
type: text/vnd.tiddlywiki
This is a version of the TaskManagementExample enhanced with the ability to drag and drop the task list to re-order them.
This is a version of the TaskManagementExample enhanced with the ability to drag and drop the task list to re-order them.<br>The list uses a the itemTemplate [[TaskManagementExampleDraggableTemplate]] tiddler, which you will also need to experiment yourself.
! Outstanding tasks
//Drag the tasks to re-order them//
<$macrocall $name='wikitext-example-without-html'
src="""//Drag the tasks to re-order them//
<<list-tagged-draggable tag:"task" subFilter:"!has[draft.of]!tag[done]" itemTemplate:"TaskManagementExampleDraggableTemplate" emptyMessage:"You don't have any active tasks">>
"""/>
! Completed tasks
//(Listed in reverse order of completion)//
<$macrocall $name='wikitext-example-without-html'
src="""//(Listed in reverse order of completion)//
<$list filter="[!has[draft.of]tag[task]tag[done]sort[modified]]">
<div>
<$checkbox tag="done"> ~~<$link/>~~</$checkbox>
</div>
</$list>
"""/>

View File

@@ -4,35 +4,36 @@ tags: Features
title: DateFormat
type: text/vnd.tiddlywiki
The default representation of dates is a compact string such as <<.value 20211002153802059>>. The associated template is `[UTC]YYYY0MM0DD0hh0mm0ss0XXX`. For example, the <<.field created>> and <<.field modified>> fields are stored like this.
The default representation of dates is a compact string such as <<.value "<$view field='modified' format='text'/>">>. The associated template is `[UTC]YYYY0MM0DD0hh0mm0ss0XXX`. For example, the <<.field created>> and <<.field modified>> fields are stored like this.
The display format for this string can be controlled with a template. For example, transcluding the <<.field modified>> field automatically applies a template to display the date as <<.value "Sat Oct 02 2021 17:40:50 GMT+0200 (Central European Summer Time)">>. A few widgets and filter operators allow you to manually specify a template, for example the ViewWidget:
The display format for this string can be controlled with a template. For example, transcluding the <<.field modified>> field automatically applies a template to display the date as "{{!!modified}}". A few widgets and filter operators allow you to manually specify a template, for example the ViewWidget:
`<$view field=modified format=date template="DDth mmm YYYY 0hh:0mm:0ss" />`
The date string is processed with the following substitutions:
|!Token |!Substituted Value |
|`[UTC]`|Time-shift the represented date to UTC. Must be at very start of format string |
|`YYYY` |Full year |
|`YY` |Two-digit year |
|`wYYYY` |Full year with respect to week number |
|`aYYYY` |<<.from-version "5.1.23">> Full year but negative dates are displayed as positive |
|`wYY` |Two digit year with respect to week number |
|`{era:BCE||CE}` |<<.from-version "5.1.23">> Displays a different string for years that are negative, zero or positive (see below) |
|`MMM` |Month in full (e.g. "July") |
|`mmm` |Short month (e.g. "Jul") |
|`MM` |Month number |
|`0MM` |Adds leading zero |
|`ddddd` |<<.from-version "5.2.0">> Day of year (1 to 365, or 366 for leap years) |
|`0ddddd` |<<.from-version "5.2.0">> Zero padded day of year (001 to 365, or 366 for leap years) |
|`DDD` |Day of week in full (eg, "Monday") |
|`ddd` |Short day of week (eg, "Mon") |
|`DDD` |Day of week in full (e.g. "Monday") |
|`ddd` |Short day of week (e.g. "Mon") |
|`dddd` |<<.from-version "5.2.0">> Weekday number from 1 through 7, beginning with Monday and ending with Sunday |
|`DD` |Day of month |
|`0DD` |Adds a leading zero |
|`DDth` |Adds a suffix |
|`WW` |ISO-8601 week number of year |
|`0WW` |Adds a leading zero |
|`MMM` |Month in full (eg, "July") |
|`mmm` |Short month (eg, "Jul") |
|`MM` |Month number |
|`0MM` |Adds leading zero |
|`YYYY` |Full year |
|`YY` |Two digit year |
|`wYYYY` |Full year with respect to week number |
|`aYYYY` |<<.from-version "5.1.23">> Full year but negative dates are displayed as positive |
|`wYY` |Two digit year with respect to week number |
|`{era:BCE||CE}` |<<.from-version "5.1.23">> Displays a different string for years that are negative, zero or positive (see below) |
|`hh` |Hours |
|`0hh` |Adds a leading zero |
|`hh12` |Hours in 12 hour clock |
@@ -43,12 +44,12 @@ The date string is processed with the following substitutions:
|`0ss` |Seconds with leading zero |
|`XXX` |Milliseconds |
|`0XXX` |Milliseconds with leading zero |
|`am` or `pm` |Lower case AM/PM indicator |
|`am` or `pm` |Lower case am/pm indicator |
|`AM` or `PM` |Upper case AM/PM indicator |
|`TZD` |Timezone offset |
|`TZD` |Timezone offset from UTC (e.g. "+01:00", "-05:00"…) |
|`TIMESTAMP` |<<.from-version "5.2.4">> Number of milliseconds since the [[ECMAScript epoch|https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#the_ecmascript_epoch_and_timestamps]], 1 January 1970. |
|`\x` |Used to escape a character that would otherwise have special meaning |
|`[UTC]`|Time-shift the represented date to UTC. Must be at very start of format string|
Note that other text is passed through unchanged, allowing commas, colons or other separators to be used.

View File

@@ -6,15 +6,13 @@ type: text/vnd.tiddlywiki
<<.operator-example 2 "[!days:created[-800]]" "tiddlers created more than 800 days ago">>
The filter can be used to highlight new items in a list. For example:
<$macrocall
$name="wikitext-example-without-html" src=
"""
<ul>
$name="wikitext-example-without-html"
src="""<ul>
<$list filter="[tag[ReleaseNotes]!<currentTiddler>!sort[modified]]">
<li>
<$link><$view field="title"/></$link>
<$list filter="[<currentTiddler>days[-180]]"> @@color:red;^^new^^@@</$list>
<$list filter="[<currentTiddler>days[-500]!days[-180]]"> @@color:black;^^recent^^@@</$list>
<$list filter="[<currentTiddler>days[-180]]"> @@color:red;^^new^^@@</$list>
<$list filter="[<currentTiddler>days[-500]!days[-180]]"> @@color:black;^^recent^^@@</$list>
</li>
</$list>
</ul>
"""/>
</ul>"""/>

View File

@@ -1,6 +1,6 @@
caption: function
created: 20220909111836951
modified: 20230419103154328
modified: 20260130210336084
op-input: a [[selection of titles|Title Selection]] passed as input to the function <<.place F>>
op-output: the [[selection of titles|Title Selection]] returned from the function <<.place F>>
op-parameter: first parameter is the [[function name|Functions]], subsequent parameters are passed to the function by position
@@ -10,7 +10,7 @@ tags: [[Filter Operators]]
title: function Operator
type: text/vnd.tiddlywiki
<<.from-version "5.3.0">> The <<.op function>> operator applies a named [[function|Functions]] to the input titles, and returns the results from the function. The function is invoked once with all of the input titles (in contrast, the [[filter Operator]] invokes its function separately for each input title).
<<.from-version "5.3.0">> The <<.op function>> operator applies a named [[function|Functions]] to the input titles, and returns the results from the function. The function is called once with all of the input titles (in contrast, the [[filter Operator]] calls its function separately for each input title).
The first parameter of the <<.op function>> operator specifies the name of the function to be called. Subsequent parameters are passed to the function.

View File

@@ -16,12 +16,13 @@ Functions are usually defined with the [[Pragma: \function]]:
\end
```
Functions can be invoked in several ways:
Functions can be called in several ways:
* Directly transclude functions with the syntax `<<myfun param:"value">>`
* Assign functions to widget attributes with the syntax `<div class=<<myfun param:"value">>>`
* Invoke functions via the [[function Operator]] with the syntax `[function[myfun],[value],...]`
* Directly invoke functions whose names contain a period as custom filter operators with the syntax `[my.fun[value]]` or `[.myfun[value]]`
* Using the [[Calls]] syntax:
** Directly transclude functions with the syntax `<<myfun param:"value">>`
** Assign functions to widget attributes with the syntax `<div class=<<myfun param:"value">>>`
* Call functions via the [[function Operator]] with the syntax `[function[myfun],[value],...]`
* Directly call functions whose names contain a period as custom filter operators with the syntax `[my.fun[value]]` or `[.myfun[value]]`
!! How Functions Work

View File

@@ -0,0 +1,43 @@
created: 20240310165023000
modified: 20260125212303316
tags: [[Call Syntax]]
title: Call Syntax
type: text/vnd.tiddlywiki
<<.preamble """What follows is a formal presentation of the syntax of the WikiText syntax for procedure/function/macro calls, using [[railroad diagrams|Railroad Diagrams]].""">>
!! callee-name
<$railroad text="""
"<<" [[ callee-name |Calls]] [: [[whitespace|"Filter Whitespace"]] [:{param-value}] ]">>"
"""/>
* The <<.place callee-name>> is a sequence of non-whitespace characters other than `(` or `>`.
* <<.place whitespace>> denotes a sequence of [[whitespace characters|Filter Whitespace]].
!!! param-value
Each ''individual'' <<.place param-value>> has the following syntax:
<$railroad text="""
\start none
\end none
(
value
|
param-name [:space] (
":" [:space] value [: space]
|
"=" [:space] new-value [: space]
)
)
"""/>
* The <<.place param-name>> is a sequence of letters (`A`--`Z`, `a`--`z`), digits (`0`--`9`), hyphens (`-`) and underscores (`_`).
* The <<.place value>> is specified as follows:
<$railroad text={{$:/editions/tw5.com/railroad/call-parameter-value}}/>
* <<.from-version 5.4.0>> The <<.place new-value>> can either be a plain <<.place value>> or a full <<.place callee-name>> call, allowing for dynamic parameter values.

View File

@@ -1,11 +1,13 @@
created: 20150220191009000
modified: 20150221111554000
title: $:/editions/tw5.com/railroad/macro-parameter-value
modified: 20260125212303316
title: $:/editions/tw5.com/railroad/call-parameter-value
type: text/vnd.tiddlywiki.railroad
( '"""' [:{/'anything but """'/}] '"""'
| '"' [:{/'anything but "'/}] '"'
| "'" [:{/"anything but '"/}] "'"
| "[[" [:{/"anything but ]"/}] "]]"
| "`" [:{/"anything but `"/}] "`"
| "```" [:{/"anything but ```"/}] "```"
| {/"""anything but ' " or whitespace"""/}
)

View File

@@ -1,31 +1,7 @@
created: 20150221105732000
modified: 20150221222352000
tags: [[Macro Syntax]] $:/deprecated
modified: 20260125212303316
tags: $:/deprecated
title: Macro Call Syntax
type: text/vnd.tiddlywiki
<<.deprecated-since "5.3.0" "Procedure Call Syntax">>
----------
<<.preamble """What follows is a formal presentation of the syntax of the WikiText syntax for macro calls, using [[railroad diagrams|Railroad Diagrams]]. A [[simpler overview|Macro Calls in WikiText]] is also available.""">>
<$railroad text="""
"<<" name [: space [:{param-value}] ]">>"
"""/>
<<.place space>> denotes a sequence of [[whitespace characters|Filter Whitespace]].
The [[macro|Macros]]'s <<.place name>> is a sequence of non-whitespace characters other than `(` or `>`.
Each individual <<.place param-value>> has the following syntax:
<$railroad text="""
[: param-name [:space] ":" [:space] ] value [: space]
"""/>
The <<.place param-name>> is a sequence of letters (`A`--`Z`, `a`--`z`), digits (`0`--`9`), hyphens (`-`) and underscores (`_`).
The <<.place value>> is specified as follows:
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<<.deprecated-since "5.3.0" "Call Syntax">>

View File

@@ -37,7 +37,7 @@ param-name [: [:space] ":" [:space] default ]
The optional <<.place default>> value of a parameter is specified as follows:
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<$railroad text={{$:/editions/tw5.com/railroad/call-parameter-value}}/>
The <<.place rest>> of the definition has the following syntax:

View File

@@ -1,33 +1,6 @@
created: 20240310165023000
modified: 20240310172648116
tags: [[Procedure Syntax]]
modified: 20260125212303316
title: Procedure Call Syntax
type: text/vnd.tiddlywiki
<<.preamble """What follows is a formal presentation of the syntax of the WikiText syntax for procedure calls, using [[railroad diagrams|Railroad Diagrams]].""">>
!! procedure-name
<$railroad text="""
"<<" [[ procedure-name |Procedures]] [: [[whitespace|"Filter Whitespace"]] [:{param-value}] ]">>"
"""/>
* The [[procedure's|Procedures]] <<.place procedure-name>> is a sequence of non-whitespace characters other than `(` or `>`.
* <<.place whitespace>> denotes a sequence of [[whitespace characters|Filter Whitespace]].
!!! param-value
Each ''individual'' <<.place param-value>> has the following syntax:
<$railroad text="""
\start none
\end none
[: param-name [:[[whitespace|"Filter Whitespace"]]] ":" [:[[whitespace|"Filter Whitespace"]]] ] value [: [[whitespace|"Filter Whitespace"]] ]
"""/>
* The <<.place param-name>> is a sequence of letters (`A`--`Z`, `a`--`z`), digits (`0`--`9`), hyphens (`-`) and underscores (`_`).
* The <<.place value>> is specified as follows:
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<<.deprecated-since "5.4.0" "Call Syntax">>

View File

@@ -1,6 +1,6 @@
created: 20240310165023000
modified: 20240310175033730
tags: [[Procedure Syntax]]
tags: [[Call Syntax]]
title: Procedure Definition Syntax
type: text/vnd.tiddlywiki
@@ -73,7 +73,7 @@ Each ''individual'' <<.place parameter>> has the following syntax:
* <<.place default>> is an optional value of a parameter is specified as follows:
<$railroad text={{$:/editions/tw5.com/railroad/macro-parameter-value}}/>
<$railroad text={{$:/editions/tw5.com/railroad/call-parameter-value}}/>
!! body

View File

@@ -6,6 +6,6 @@ type: text/vnd.tiddlywiki
Plain text description can be found at [[Procedures]]
<<list-links filter:"[tag[Procedure Syntax]]">>
<<list-links filter:"[tag[Call Syntax]]">>
<<.tip "The railroad boxes in the linked tiddlers can be used to navigate.">>

View File

@@ -1,6 +1,6 @@
caption: tag-pill
created: 20161128190930538
modified: 20161128191220364
modified: 20260114112210310
tags: Macros [[Core Macros]]
title: tag-pill Macro
type: text/vnd.tiddlywiki
@@ -9,13 +9,18 @@ The <<.def tag-pill>> [[macro|Macros]] generates a static tag pill showing a spe
!! Parameters
;tag
; tag
: The title of the tag
;element-tag
: The element name to be used for the pill (defaults to "span")
;element-attributes
: Additional attributes for the pill element
;actions
: Action widgets to be triggered when the pill is clicked. Within the text, the macro parameter ''tag'' contains the title of the selected tag.
; element-tag
: The element name to be used for the pill (defaults to HTML element SPAN).
: If an ''actions'' parameter is used the element-tag needs to be set to `$button`
; element-attributes
: Additional attributes for the element specified in ''element-tag''
; actions
: If an actions parameter should be activated, the ''element-tag'' parameter needs to be set to `$button`.
: Action widgets to be triggered when the pill is clicked. Within the text, the macro parameter ''tag'' contains the title of the selected tag
<<.macro-examples "tag-pill">>

View File

@@ -1,56 +1,7 @@
caption: Procedure Calls
created: 20221007130006705
modified: 20230419103154329
tags: WikiText Procedures
modified: 20260125212303316
title: Procedure Calls
type: text/vnd.tiddlywiki
!! Introduction
This tiddler describes the different ways in which [[procedure|Procedures]] can be called.
!! Procedure Call Transclusion Shortcut
To call a [[procedure|Procedures]], place `<<`double angle brackets`>>` around the name and any parameter values.
```
<<my-procedure param:"This is the parameter value">>
```
By default, parameters are listed in the same order as in the procedure definition. A parameter can be labelled with its name and a colon to allow them to be listed in a different order.
If no value is specified for a parameter, the default value given for that parameter in the [[procedure definition|Procedure Definitions]] is used instead. (If no default value was defined, the parameter is blank).
Each parameter value can be enclosed in `'`single quotes`'`, `"`double quotes`"`, `"""`triple double quotes`"""` or `[[`double square brackets`]]`. Triple double quotes allow a value to contain almost anything. If a value contains no spaces or single or double quotes, it requires no delimiters.
See the discussion about [[parser modes|WikiText parser mode: macro examples]]
!! Procedure Calls with <<.wlink TranscludeWidget>> Widget
The shortcut syntax expands to the <<.wlink TranscludeWidget>> widget with the `$variable` attribute specifying the name of the procedure to transclude.
```
<$transclude $variable="my-procedure" param="This is the parameter value"/>
```
The widget itself offers greater flexibility than the shortcut syntax, including the ability to specify dynamic parameter values.
!! Assigning Procedure Calls to Attribute Values
The text of a procedure can be directly assigned to an attribute of a widget or HTML element. The result of the procedure is not wikified, which means that [[parameter handling|Procedure Parameter Handling]] does not take place.
```
<div class=<<myclasses>>>
...
</div>
```
!! Using Procedure Calls in Filters
Procedure calls can be used in filters. The text is not wikified which again means that the parameters will be ignored.
```
<$list filter="[<my-procedure>]">
...
</$list>
```
<<.deprecated-since "5.4.0" "Calls">>

View File

@@ -33,6 +33,6 @@ Procedures are implemented as a special kind of [[variable|Variables]]. The only
!! Using Procedures
* [[Procedure Definitions]] describes how to create procedures
* [[Procedure Calls]] describes how to use procedures
* [[Calls]] describes how to use procedures
* [[Procedure Parameter Handling]] describes how procedure parameters work
* [[Procedure Syntax]] is a formal syntax description using railroad diagrams
* [[Call Syntax]] is a formal syntax description using railroad diagrams

View File

@@ -0,0 +1,56 @@
caption: Calls
created: 20221007130006705
modified: 20260125212303316
tags: WikiText Procedures Functions Macros
title: Calls
type: text/vnd.tiddlywiki
!! Introduction
This tiddler describes the different ways in which [[procedures|Procedures]], [[functions|Functions]] and [[macros|Macros]] can be called. See [[Call Syntax]] for a formal description of the syntax.
!! Call Transclusion Shortcut
To perform a call, place `<<`double angle brackets`>>` around the callee name and any parameter values.
```
<<my-procedure param="This is the parameter value">>
```
By default, parameters are interpreted as being in the same order as in the definition. A parameter value can be labelled with its name and an equals sign to allow them to be listed in a different order.
If no value is specified for a parameter, the default value given for that parameter in the [[procedure definition|Procedure Definitions]], [[function definition|Function Definitions]] or [[macro definition|Macro Definitions]] is used instead. (If no default value was defined, the parameter is blank).
Each parameter value can be enclosed in `'`single quotes`'`, `"`double quotes`"`, `"""`triple double quotes`"""` or `[[`double square brackets`]]`. Triple double quotes allow a value to contain almost anything. If a value contains no spaces or single or double quotes, it requires no delimiters. [[Substituted Attribute Values]] enclosed in single or triple back quotes are also supported.
See the discussion about [[parser modes|WikiText parser mode: macro examples]]
!! Calls with <<.wlink TranscludeWidget>> Widget
The shortcut syntax expands to the <<.wlink TranscludeWidget>> widget with the `$variable` attribute specifying the name of the procedure to transclude.
```
<$transclude $variable="my-procedure" param="This is the parameter value"/>
```
The widget itself offers greater flexibility than the shortcut syntax, including the ability to override it with a custom widget.
!! Assigning Results of Calls to Attribute Values
The text returned from a call can be directly assigned to an attribute of a widget or HTML element. The result of the call is not wikified, which means that [[parameter handling|Procedure Parameter Handling]] does not take place.
```
<div class=<<myclasses>>>
...
</div>
```
!! Using Calls in Filters
Calls can be used in filters. The text is not wikified which again means that the parameters will be ignored.
```
<$list filter="[<my-procedure>]">
...
</$list>
```

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#8093
description: Fixes SelectWidget does not work with multiple options organised into group - issue #8092
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: bugfix
change-category: widget
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/issues/8093 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9616
github-contributors: buggyj saqimtiaz
Fixed SelectWidget does not work with multiple options organised into group.

View File

@@ -0,0 +1,42 @@
title: $:/changenotes/5.4.0/#9055
description: Dynamic parameters for macro/procedure/function calls
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: hackability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9055
github-contributors: Jermolene
This PR extends the handling of macro/procedure/function made via the `<<..>>` syntax to allow parameters to be specified dynamically instead of just as static strings. To indicate the new syntax the colon that usually separates a parameter name from its value is replaced by an equals sign.
For example, by it is now possible to do things like this:
```
<<mymacro param={{Something}}>>
```
Or even this:
```
<div class=<<mymacro param={{Something}}>>>
```
Or this:
```
<div class=<<mymacro param={{{ [<myvar>addprefix[https:] }}}>>>
```
Parameters can also be specified for the inner call:
```
<div class=<<mymacro param={{{ [<innermacro p={{Something}}>addprefix[https:] }}}>>>
```
The extended syntax can be used in three different settings:
* As a standalone construction
* As a widget attribute value
* As a filter operand value
In all cases, it is now possible to use an equals sign instead of a colon to allow parameter values to be passed as a transclusion, filter expression or nested call.

View File

@@ -0,0 +1,17 @@
change-category: nodejs
change-type: feature
created: 20260120154012282
description: Allows server routes to be prioritized via ordering.
github-contributors: saqimtiaz
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9206
modified: 20260120160656948
release: 5.4.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.4.0/#9206
type: text/vnd.tiddlywiki
This PR adds support for an info property to server route module exports. The info object may include a priority field, which determines the routes order of precedence.
Priorities are numeric and follow a descending order: routes with higher priority values are processed first, similar to how saver modules are prioritized.
To maintain backward compatibility with existing code, any module that omits info or info.priority is assigned a default priority of 100. Core server routes have been updated to explicitly use this default value of 100.

View File

@@ -0,0 +1,13 @@
change-category: nodejs
change-type: feature
created: 20260120154249928
description: Allows server routes to support multiple HTTP methods.
github-contributors: saqimtiaz
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9207
modified: 20260120160159661
release: 5.4.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.4.0/#9207
type: text/vnd.tiddlywiki
Allows server routes to support multiple HTTP methods by introducing an `exports.methods` array.

View File

@@ -0,0 +1,13 @@
change-category: widget
change-type: deprecation
created: 20260120154533983
description: The deprecated events and actions-* atrributes for the eventcatcher widget have been removed.
github-contributors: saqimtiaz
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9259
modified: 20260120160236297
release: 5.4.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.4.0/#9259
type: text/vnd.tiddlywiki
Deprecates and removes the `events` and `actions-*` attributes for the $eventcatcher widget.

View File

@@ -0,0 +1,8 @@
changenote: $:/changenotes/5.4.0/#9259
created: 20260120154817011
description: Deprecated events and actons-* attributes from the eventcatcher widget
impact-type: deprecation
modified: 20260120154900978
tags: $:/tags/ImpactNote
title: $:/changenotes/5.4.0/#9259/impacts/deprecate-eventcatcher-attributes
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,29 @@
change-category: hackability
change-type: feature
created: 20260120154445701
description: Adds info tiddlers for viewport dimensions that are updated on window resize.
github-contributors: saqimtiaz
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9260
modified: 20260120160515462
release: 5.4.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.4.0/#9260
type: text/vnd.tiddlywiki
Adds info tiddlers for viewport dimensions that are updated on window resize.
!! Example: Main and a user-created window with windowID my-window
|Window | Info tiddler | Meaning |h
|system/main |`$:/info/browser/window/system/main/outer/width` | Full browser window including chrome, tabs, toolbars |
|system/main |`$:/info/browser/window/system/main/outer/height` | Full browser window including chrome, tabs, toolbars |
|system/main |`$:/info/browser/window/system/main/inner/width` | Viewport width including scrollbars |
|system/main |`$:/info/browser/window/system/main/inner/height` | Viewport height including scrollbars |
|system/main |`$:/info/browser/window/system/main/client/width` | Content width excluding scrollbars |
|system/main |`$:/info/browser/window/system/main/client/height` | Content height excluding scrollbars |
|user/my-window |`$:/info/browser/window/user/my-window/outer/width` | Full browser window including chrome, tabs, toolbars |
|user/my-window |`$:/info/browser/window/user/my-window/outer/height` | Full browser window including chrome, tabs, toolbars |
|user/my-window |`$:/info/browser/window/user/my-window/inner/width` | Viewport width including scrollbars |
|user/my-window |`$:/info/browser/window/user/my-window/inner/height` | Viewport height including scrollbars |
|user/my-window |`$:/info/browser/window/user/my-window/client/width` | Content width excluding scrollbars |
|user/my-window |`$:/info/browser/window/user/my-window/client/height` | Content height excluding scrollbars |

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9277
description: Added an option to enable CORS
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: feature
change-category: developer
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9277
github-contributors: kixam
Added an option to the TiddlyWiki5 server to enable CORS (ie. don't check `same-origin`). It is meant for advanced users, do not use it unless you understand the full consequences.

View File

@@ -1,17 +1,7 @@
title: $:/changenotes/5.4.0/#9337/compatibility-break/math-filters
title: $:/changenotes/5.4.0/#9337/impacts/math-filters
changenote: $:/changenotes/5.4.0/#9337
created - 20251112152513384
modified - 20251112152513384
created: 20251112152513384
modified: 20251209160312626
tags: $:/tags/ImpactNote
description: filter output with empty input changes for some math filter operators
impact-type: compatibility-break
These math operators will now output an empty list when the input list is empty:
* sum[] - previously returned 0
* product[] - previously returned 1
* maxall[] - previously returned -Infinity
* minall[] - previously returned Infinity
* average[] - previously returned NaN
* variance[] - previously returned NaN
* standard-deviation[] - previously returned NaN
description: filter output changes for some math filter operators when input list is empty
impact-type: compatibility-break

View File

@@ -4,7 +4,8 @@ release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: translation
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9375
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9375 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9576
github-contributors: BramChen
* change camel-case hint text for chinese translations
* change camel-case hint text for chinese translations
* add alerts ARIA message

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9494
description: Fix LetWidget to always set all staged variables on first render
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: bugfix
change-category: widget
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9494
github-contributors: yaisog
This PR corrects a bug where the LetWidget did not set variables if their value was the empty output of a filtered transclusion.

View File

@@ -0,0 +1,15 @@
title: $:/changenotes/5.4.0/#9551
description: Add words and lines modes to diff-text widget
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: widget
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9551
github-contributors: yaisog
The DiffTextWidget now supports two additional diff modes via the `mode` attribute:
* `mode="words"` - Performs word-level diff operations, making differences more intelligible when comparing text
* `mode="lines"` - Performs line-level diff operations, highlighting entire lines that have changed
The default `mode="chars"` continues to work as before, performing character-level diff operations.

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9600
description: Fix Ctrl-Enter not working in EditTemplate tag name input
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: bugfix
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9600
github-contributors: yaisog
The tag name input now calls `<<save-tiddler-actions>>` from the EditTemplate when Ctrl-Enter (or whichever key is assigned to input-accept-variant) is pressed.

View File

@@ -0,0 +1,12 @@
change-category: usability
change-type: bugfix
created: 20260125195754439
description: Refresh widget if "default" parameter input value is changed
github-contributors: pmario
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9217
modified: 20260125195754439
release: 5.4.0
tags: $:/tags/ChangeNote
title: $:/changenotes/5.4.0/#9217
type: text/vnd.tiddlywiki

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9565
description: Add stylesheet wiki information
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: feature
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9565
github-contributors: Leilei332
Extend wiki information tool to display stylesheet information.

View File

@@ -0,0 +1,18 @@
title: $:/changenotes/5.4.0/#9513
description: Bump markdown-it and its plugins to newest version
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: plugin
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9513
github-contributors: Leilei332
Upgrade the markdown-it libraries used by the [[Markdown Plugin]]:
* markdown-it: 14.1.0
* markdown-it-deflist: 3.0.0
* markdown-it-footnote: 4.0.0
* markdown-it-ins: 4.0.0
* markdown-it-mark: 4.0.0
* markdown-it-sub: 2.0.0
* markdown-it-sup: 2.0.0

View File

@@ -4,7 +4,7 @@ release: 5.4.0
tags: $:/tags/ChangeNote
change-type: deprecation
change-category: developer
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9251
github-contributors: Leilei332
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9251 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9622
github-contributors: Leilei332 saqimtiaz
Deprecate some utility functions. Some of them are moved to [[$:/core/modules/utils/deprecated.js]].

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9475
description: Split escapecss.js into two platforms
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: performance
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9475
github-contributors: Leilei332
Split [[$:/core/modules/utils/escapecss.js]] for two platforms: one for the browser, the other for Node.js. The `CSS.escape` polyfill is moved to `core-server`.

View File

@@ -0,0 +1,10 @@
title: $:/changenotes/5.4.0/#9248
description: Improve alert accessibility
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: usability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9248 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9575
github-contributors: Leilei332

View File

@@ -5,8 +5,16 @@ tags: Releases
title: TiddlyWiki Releases
type: text/vnd.tiddlywiki
Here are the details of recent releases of TiddlyWiki5. See [[TiddlyWiki5 Versioning]] for details of how releases are named, and [[Release Notes and Changes]] for details of how release notes are constructed.
Here are the details of recent releases of TiddlyWiki5. See [[TiddlyWiki5 Versioning]] for details of how releases are named.
* An overview about all TW versions can be found at the [[TiddlyWiki Archive]].
* If you are using Node.js, you can also install ''prior'' versions like this:
*> npm install -g tiddlywiki@5.3.0
* BetaReleases and AlphaReleases are listed separately
<$list filter="[tag[ReleaseNotes]!sort[created]limit[1]]">
<$macrocall $name="tabs" tabsList="[tag[ReleaseNotes]!sort[created]]" default={{!!title}} class="tc-vertical" template="ReleaseTemplate" />
</$list>
</$list>

View File

@@ -1,5 +1,5 @@
created: 20230803034230294
modified: 20230803043848449
modified: 20260114112240512
tags: [[Macro Examples]] [[tag-pill Macro]]
title: tag-pill Macro (Examples)
@@ -12,3 +12,9 @@ This example displays the [[Definitions]] tag as an unclickable, but still-style
<$transclude $variable=".example" n="2" eg="""<<tag-pill Definitions element-tag:"big" element-attributes:"inert">>"""/>
<$transclude $variable=".example" n="3" eg="""\procedure tag-actions()
<$action-confirm $message="test"/>
\end
<$transclude $variable="tag-pill" tag="asdf" element-tag="$button" actions=<<tag-actions>>/>
""">>

View File

@@ -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>
"""/>

View File

@@ -0,0 +1,52 @@
created: 20230726145210484
modified: 20260130210336084
tags: [[Variable Usage]]
title: Behaviour of called variables depends on how the variable was declared
type: text/vnd.tiddlywiki
\define m1(a1) $a1$ - <<__a1__>> - <<a1>>
\procedure p1(a1) $a1$ - <<__a1__>> - <<a1>>
\function f1(a1) "$a1$" "-" [<__a1__>] ="-" [<a1>] :and[join[ ]]
Called in normal wikitext context: `<$transclude $variable=myvar/>` or `<<myvar>>`
{{Behaviour of variables called via normal wikitext}}
Called via widget attribute: `<div class=<<myvar>>/>`
{{Behaviour of variables called via widget attributes}}
Called via filter operator parameter: `[<myvar>]`
{{Behaviour of variables called via filter operator parameter}}
Called via function call in a filter expression: `[function[.myfun]]`
{{Behaviour of variables called via filter expression function call}}
!! Examples
Below is an example macro, procedure and function definition. All three forms of parameter substitution `$a1$`, `<<__a1__>>`, and `<<a1>>` are included in each definition. The output helps illustrate when each form of substitution will or will not have affect.
```
\define m1(a1) $a1$ - <<__a1__>> - <<a1>>
\procedure p1(a1) $a1$ - <<__a1__>> - <<a1>>
\function f1(a1) $a1$ "-" [<__a1__>] ="-" [<a1>] :and[join[ ]]
```
| !Variable transclusion|!output |
| `<<m1 foo>>`|<<m1 foo>>|
| `<<p1 foo>>`|<<p1 foo>>|
| `<<f1 foo>>`|<<f1 foo>>|
| !Widget attribute|!output |
| `<$text text=<<m1 foo>>/>`|<$text text=<<m1 foo>>/>|
| `<$text text=<<p1 foo>>/>`|<$text text=<<p1 foo>>/>|
| `<$text text=<<f1 foo>>/>`|<$text text=<<f1 foo>>/>|
| !Filter operator parameter|!output |
| `[<m1 foo>]`|<$text text={{{[<m1 foo>]}}}/>|
| `[<p1 foo>]`|<$text text={{{[<p1 foo>]}}}/>|
| `[<f1 foo>]`|<$text text={{{[<f1 foo>]}}}/>|
| !Function call in filter expression|!output |
| `[function[m1],[foo]]`|<$text text={{{[function[m1],[foo]]}}}/>|
| `[function[p1],[foo]]`|<$text text={{{[function[p1],[foo]]}}}/>|
| `[function[f1],[foo]]`|<$text text={{{[function[f1],[foo]]}}}/>|

View File

@@ -1,52 +1,6 @@
created: 20230726145210484
modified: 20240619211734149
tags: [[Variable Usage]]
title: Behaviour of invoked variables depends on how the variable was declared
modified: 20260130210336084
title: Behaviour of called variables depends on how the variable was declared
type: text/vnd.tiddlywiki
\define m1(a1) $a1$ - <<__a1__>> - <<a1>>
\procedure p1(a1) $a1$ - <<__a1__>> - <<a1>>
\function f1(a1) "$a1$" "-" [<__a1__>] ="-" [<a1>] :and[join[ ]]
Invoked in normal wikitext context: `<$transclude $variable=myvar/>` or `<<myvar>>`
{{Behaviour of variables invoked via normal wikitext}}
Invoked via widget attribute: `<div class=<<myvar>>/>`
{{Behaviour of variables invoked via widget attributes}}
Invoked via filter operator parameter: `[<myvar>]`
{{Behaviour of variables invoked via filter operator parameter}}
Invoked via function call in a filter expression: `[function[.myfun]]`
{{Behaviour of variables invoked via filter expression function call}}
!! Examples
Below is an example macro, procedure and function definition. All three forms of parameter substitution `$a1$`, `<<__a1__>>`, and `<<a1>>` are included in each definition. The output helps illustrate when each form of substitution will or will not have affect.
```
\define m1(a1) $a1$ - <<__a1__>> - <<a1>>
\procedure p1(a1) $a1$ - <<__a1__>> - <<a1>>
\function f1(a1) $a1$ "-" [<__a1__>] ="-" [<a1>] :and[join[ ]]
```
| !Variable transclusion|!output |
| `<<m1 foo>>`|<<m1 foo>>|
| `<<p1 foo>>`|<<p1 foo>>|
| `<<f1 foo>>`|<<f1 foo>>|
| !Widget attribute|!output |
| `<$text text=<<m1 foo>>/>`|<$text text=<<m1 foo>>/>|
| `<$text text=<<p1 foo>>/>`|<$text text=<<p1 foo>>/>|
| `<$text text=<<f1 foo>>/>`|<$text text=<<f1 foo>>/>|
| !Filter operator parameter|!output |
| `[<m1 foo>]`|<$text text={{{[<m1 foo>]}}}/>|
| `[<p1 foo>]`|<$text text={{{[<p1 foo>]}}}/>|
| `[<f1 foo>]`|<$text text={{{[<f1 foo>]}}}/>|
| !Function call in filter expression|!output |
| `[function[m1],[foo]]`|<$text text={{{[function[m1],[foo]]}}}/>|
| `[function[p1],[foo]]`|<$text text={{{[function[p1],[foo]]}}}/>|
| `[function[f1],[foo]]`|<$text text={{{[function[f1],[foo]]}}}/>|
See [[Behaviour of called variables depends on how the variable was declared]].

View File

@@ -6,5 +6,5 @@ type: text/vnd.tiddlywiki
|tc-first-col-min-width|k
|!how declared|!behaviour|
|\define, <<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|Every function is a variable, but only variables defined using \function are invokable using the <<.olink function>> filter operator. Attempts to use a non-function variable is the same as if the function doesn't exist. The behavior in this case is like the identity function. All filter input is passed unchanged to the output.|
|\define, <<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|Every function is a variable, but only variables defined using \function are callable using the <<.olink function>> filter operator. Attempts to use a non-function variable is the same as if the function doesn't exist. The behavior in this case is like the identity function. All filter input is passed unchanged to the output.|
|\function|The body text of the function is treated as a filter expression and evaluated. This filter expression can itself contain a function call. Filter expressions can be factored out into functions arbitrarily deep.|

View File

@@ -1,69 +1,85 @@
caption: diff-text
created: 20180316162725329
modified: 20251117054552220
modified: 20260102132650194
tags: Widgets
title: DiffTextWidget
type: text/vnd.tiddlywiki
! Introduction
<<.from-version "5.1.16">> The diff text widget analyses the differences between a pair of source and destination text strings and displays the results as highlighted insertions and deletions (similar to the "track changes" function of a word processor). For example:
<<.from-version "5.1.16">> The diff text widget analyses the differences between a pair of source and destination text strings and displays the results as highlighted insertions and deletions (similar to the "track changes" function of a word processor).
```
<$diff-text source="This is the original text" dest="This is the text to compare to" mode="words>
These are the <<diff-count>> differences:
</$diff-text>
```
<$diff-text source="Hey Jude, don't make it bad. Take a sad song and make it better. Remember to let her into your heart
Then you can start to make it better." dest="Hey Jude, don't be afraid. You were made to go out and get her. The minute you let her under your skin. Then you begin to make it better."/>
! Content and Attributes
!! Content
The content of the <<.wid diff-text>> widget is displayed immediately before the differences. Within the content, the variable <<.var diff-count>> is available, containing the number of differences found. If the widget has no content then it automatically transcludes the tiddler [[$:/language/Diffs/CountMessage]].
The content of the `<$diff-text>` widget is rendered immediately before the diffs. Within it, the variable `diff-count` is available, containing the number of differences found. If the widget has no content then it automatically transcludes the tiddler [[$:/language/Diffs/CountMessage]].
<<<
In other words, these three invocations are all equivalent:
```
<$diff-text source={{FirstTiddler}} dest={{SecondTiddler}}>
{{$:/language/Diffs/CountMessage}}
</$diff-text>
<$diff-text source={{FirstTiddler}} dest={{SecondTiddler}}>
</$diff-text>
<$diff-text source={{FirstTiddler}} dest={{SecondTiddler}}/>
```
<<<
!! Attributes
<<.note """The algorithm counts changes as both insertion and deletion, and therefore the number of differences can be higher than expected.""">>
|!Attribute |!Description |
|source |The source text |
|dest |The destination text |
|cleanup |Defines a way to allow diffs to be human readable |
|editcost |<<.from-version "5.4.0">> Only active if the cleanup flag is set to "efficient" |
|<<.attr source>> |The source text |
|<<.attr dest>> |The destination text |
|<<.attr cleanup>> |Optional post-processing to improve readability (default is <<.value semantic>>) |
|<<.attr editcost>> |<<.from-version "5.4.0">> Threshold parameter for <<.value efficiency>> cleanup mode (default is <<.value 4>>) |
|<<.attr mode>> |<<.from-version "5.4.0">> Specifies the granularity at which differences are computed and displayed (default is <<.value chars>>) |
!!! Cleanup Flags
!! <<.attr cleanup>> / <<.attr editcost>>
The ''cleanup'' attribute determines which optional post-processing should be applied to the diffs:
The <<.attr cleanup>> attribute determines which optional post-processing should be applied to the diffs:
* ''none'': no cleanup is performed
* ''semantic'' (default): rewrites the diffs for human readability
* ''efficient'': rewrites the diffs to minimise the number of operations for subsequent processing
** If efficient is defined, ''editcost'' defines how the cleanup algorithm for human readability works. See example slider
* <<.value none>>: No cleanup is performed
* <<.value semantic>> (default): Optimizes the differences for readability
* <<.value efficiency>>: Optimizes the differences to minimise the number of operations for subsequent processing
** When using <<.value efficiency>> mode, the <<.attr editcost>> parameter controls the cost threshold for the cleanup algorithm, determining how aggressively the diff algorithm merges nearby edits for better human readability (default value is 4).
<<.note """Note that in many cases the results will be the same regardless of the cleanup option. See the [[docs|https://github.com/google/diff-match-patch/wiki/API]] of the underlying library for more details""">>
!! <<.attr mode>>
The <<.attr mode>> attribute determines how differences are computed and displayed:
* <<.value chars>>: Compares differences at the //character level// for precise change detection
* <<.value words>>: Compares differences at the //word level// for more readable text comparisons
* <<.value lines>>: Compares differences at the //line level// for better visibility of structural changes
! Examples
In this example we compare two texts:
A basic example:
<$macrocall $name='wikitext-example-without-html'
src="""|tc-max-width tc-edit-max-width|k
<<.example n:1 e.g."""<$diff-text source="The quick brown fox jumps" dest="The slick brown fox leaps"/>""">>
In <<.value words>> mode, differences are computed at the words level:
<<.example n:2 e.g."""<$diff-text mode="words" source="The quick brown fox jumps" dest="The slick brown fox leaps"/>""">>
To see the effects of all parameters, use this example:
|tc-max-width tc-edit-max-width|k
|<$edit-text tiddler="SampleTiddlerFirst" rows="5"/>|<$edit-text tiddler="SampleTiddlerSecond" rows="5"/>|
Edit cost: {{$:/temp/SampleTiddlerEditCost}} -- Drag to 7 and then to 33
<$range tiddler="$:/temp/SampleTiddlerEditCost" min="1" max="200" default="4" class="tc-max-width"/>
<$diff-text source={{SampleTiddlerFirst}} dest={{SampleTiddlerSecond}} cleanup={{{ [{!!cleanup}!is[blank]else[efficiency]] }}} editcost={{{ [{!!editcost}!is[blank]else[4]] }}} mode={{{ [{!!mode}!is[blank]else[chars]] }}}/>
<$diff-text source={{SampleTiddlerFirst}} dest={{SampleTiddlerSecond}} cleanup=efficiency editcost={{$:/temp/SampleTiddlerEditCost}}/>
"""/>
!! <<.attr mode>>
<$radio field="mode" value="chars" default="chars" class="tc-small-gap-right"> <<.value chars>></$radio>
<$radio field="mode" value="words" class="tc-small-gap-right"> <<.value words>></$radio>
<$radio field="mode" value="lines"> <<.value lines>></$radio>
!! <<.attr cleanup>>
<$radio field="cleanup" value="none" class="tc-small-gap-right"> <<.value none>></$radio>
<$radio field="cleanup" value="semantic" class="tc-small-gap-right"> <<.value semantic>></$radio>
<$radio field="cleanup" value="efficiency" default="efficiency"> <<.value efficiency>></$radio>
<% if [{!!cleanup}!match[none]!match[semantic]] %>
!! <<.attr editcost>>: <$transclude $variable=".value" _={{{ [{!!editcost}!is[blank]else[4]] }}} />
<$range field="editcost" min="1" max="200" default="4" class="tc-max-width" style.max-width="500px" />
<% endif %>

View File

@@ -1,58 +1,7 @@
caption: Macro Calls
created: 20150220182252000
modified: 20230419103154328
tags: WikiText Macros
title: Macro Calls
type: text/vnd.tiddlywiki
!! Introduction
This tiddler describes the different ways in which [[macros|Macros]] can be called.
!! Macro Call Transclusion Shortcut
To call a [[macro|Macros]], place `<<`double angle brackets`>>` around the name and any parameter values.
```
<<mymacro param:"This is the parameter value">>
```
By default, parameters are listed in the same order as in the macro's definition. A parameter can be labelled with its name and a colon to allow them to be listed in a different order.
If no value is specified for a parameter, the default value given for that parameter in the [[macro definition|Macro Definitions]] is used instead. (If no default value was defined, the parameter is blank).
Each parameter value can be enclosed in `'`single quotes`'`, `"`double quotes`"`, `"""`triple double quotes`"""` or `[[`double square brackets`]]`. Triple double quotes allow a value to contain almost anything. If a value contains no spaces or single or double quotes, it requires no delimiters.
A more formal [[presentation|Macro Call Syntax]] of this syntax is also available.
See some [[examples|Macro Calls in WikiText (Examples)]] and discussion about [[parser modes|WikiText parser mode: macro examples]].
!! Macro Calls with <<.wlink TranscludeWidget>> Widget
The shortcut syntax expands to the <<.wlink TranscludeWidget>> widget with the `$variable` attribute specifying the name of the macro to transclude.
```
<$transclude $variable="mymacro" param="This is the parameter value"/>
```
The widget itself offers greater flexibility than the shortcut syntax, including the ability to specify parameter values.
!! Assigning Macro Calls to Attribute Values
The result of a macro can be directly assigned to an attribute of a widget or HTML element. The result of the macro is not wikified, but the [[parameter substitution|Macro Parameter Handling]] is performed.
```
<div class=<<myclasses "Horizontal">>>
...
</div>
```
!! Using Macro Calls in Filters
Macro calls can be used in filters:
```
<$list filter="[<mymacro param:'value'>]">
...
</$list>
```
<<.deprecated-since "5.4.0" "Calls">>

View File

@@ -104,7 +104,7 @@ js.configs.recommended,
"init-declarations": "off",
"@stylistic/jsx-quotes": "error",
"@stylistic/key-spacing": "off",
"@stylistic/keyword-spacing": ["error", {
"@stylistic/keyword-spacing": ["warn", {
before: true,
after: false,
overrides: {
@@ -114,6 +114,7 @@ js.configs.recommended,
return: { after: true },
throw: { after: true },
try: { after: true },
const: { after: true }
},
}],
"@stylistic/line-comment-position": "off",
@@ -290,10 +291,12 @@ js.configs.recommended,
"@stylistic/wrap-iife": "off",
"@stylistic/wrap-regex": "off",
"@stylistic/yield-star-spacing": "error",
yoda: "off",
// temporary rules
"yoda": "off",
"no-useless-escape": "off",
"no-unused-vars": "warn",
"no-unused-vars": ["warn", {
"args": "none",
"caughtErrors": "none"
}],
"no-empty": "off",
"@stylistic/no-extra-semi": "off",
"no-redeclare": "off",

View File

@@ -1,5 +1,6 @@
title: $:/language/
Alerts: 警报信息
AboveStory/ClassicPlugin/Warning: 您似乎要加载为 ~TiddlyWiki 经典版设计的插件。请注意,[[这些插件无法运行于 TiddlyWiki 5.x.x 版|https://tiddlywiki.com/#TiddlyWikiClassic]]。检测到 ~TiddlyWiki 经典版插件:
BinaryWarning/Prompt: 此条目包含二进制数据
ClassicWarning/Hint: 此条目以经典版 TiddlyWiki 标记格式撰写,不完全兼容新版 TiddlyWiki 的格式详细信息请参阅https://tiddlywiki.com/static/Upgrading。

View File

@@ -1,5 +1,6 @@
title: $:/language/
Alerts: 警示訊息
AboveStory/ClassicPlugin/Warning: 您似乎要載入為 ~TiddlyWiki 經典版設計的插件。請注意,[[這些插件無法運行於 TiddlyWiki 5.x.x 版|https://tiddlywiki.com/#TiddlyWikiClassic]]。偵測到 ~TiddlyWiki 經典版插件:
BinaryWarning/Prompt: 此條目包含二進位資料
ClassicWarning/Hint: 此條目以經典版 TiddlyWiki 標記格式撰寫,不完全相容新版 TiddlyWiki 的格式詳細資訊請參閱https://tiddlywiki.com/static/Upgrading。

View File

@@ -1,7 +1,2 @@
/*!
markdown-it-deflist
https://github.com/markdown-it/markdown-it-deflist
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownitDeflist=e()}}((function(){return function e(t,n,r){function i(f,d){if(!n[f]){if(!t[f]){var s="function"==typeof require&&require;if(!d&&s)return s(f,!0);if(o)return o(f,!0);var u=new Error("Cannot find module '"+f+"'");throw u.code="MODULE_NOT_FOUND",u}var a=n[f]={exports:{}};t[f][0].call(a.exports,(function(e){return i(t[f][1][e]||e)}),a,a.exports,e,t,n,r)}return n[f].exports}for(var o="function"==typeof require&&require,f=0;f<r.length;f++)i(r[f]);return i}({"/":[function(e,t,n){"use strict";t.exports=function(e){var t=e.utils.isSpace;function n(e,t){var n,r,i=e.bMarks[t]+e.tShift[t],o=e.eMarks[t];return i>=o||126!==(r=e.src.charCodeAt(i++))&&58!==r||i===(n=e.skipSpaces(i))||n>=o?-1:i}e.block.ruler.before("paragraph","deflist",(function(e,r,i,o){var f,d,s,u,a,l,p,k,c,h,b,y,m,g,C,I,v,_,w,x;if(o)return!(e.ddIndent<0)&&n(e,r)>=0;if((c=r+1)>=i)return!1;if(e.isEmpty(c)&&++c>=i)return!1;if(e.sCount[c]<e.blkIndent)return!1;if((d=n(e,c))<0)return!1;p=e.tokens.length,w=!0,(x=e.push("dl_open","dl",1)).map=l=[r,0],u=r,s=c;e:for(;;){for(_=!1,(x=e.push("dt_open","dt",1)).map=[u,u],(x=e.push("inline","",0)).map=[u,u],x.content=e.getLines(u,u+1,e.blkIndent,!1).trim(),x.children=[],x=e.push("dt_close","dt",-1);;){for((x=e.push("dd_open","dd",1)).map=a=[c,0],v=d,k=e.eMarks[s],h=e.sCount[s]+d-(e.bMarks[s]+e.tShift[s]);v<k&&(f=e.src.charCodeAt(v),t(f));)9===f?h+=4-h%4:h++,v++;if(d=v,I=e.tight,b=e.ddIndent,y=e.blkIndent,C=e.tShift[s],g=e.sCount[s],m=e.parentType,e.blkIndent=e.ddIndent=e.sCount[s]+2,e.tShift[s]=d-e.bMarks[s],e.sCount[s]=h,e.tight=!0,e.parentType="deflist",e.md.block.tokenize(e,s,i,!0),e.tight&&!_||(w=!1),_=e.line-s>1&&e.isEmpty(e.line-1),e.tShift[s]=C,e.sCount[s]=g,e.tight=I,e.parentType=m,e.blkIndent=y,e.ddIndent=b,x=e.push("dd_close","dd",-1),a[1]=c=e.line,c>=i)break e;if(e.sCount[c]<e.blkIndent)break e;if((d=n(e,c))<0)break;s=c}if(c>=i)break;if(u=c,e.isEmpty(u))break;if(e.sCount[u]<e.blkIndent)break;if((s=u+1)>=i)break;if(e.isEmpty(s)&&s++,s>=i)break;if(e.sCount[s]<e.blkIndent)break;if((d=n(e,s))<0)break}return x=e.push("dl_close","dl",-1),l[1]=c,e.line=c,w&&function(e,t){var n,r,i=e.level+2;for(n=t+2,r=e.tokens.length-2;n<r;n++)e.tokens[n].level===i&&"paragraph_open"===e.tokens[n].type&&(e.tokens[n+2].hidden=!0,e.tokens[n].hidden=!0,n+=2)}(e,p),!0}),{alt:["paragraph","reference","blockquote"]})}},{}]},{},[])("/")}));
/*! markdown-it-deflist 3.0.0 https://github.com/markdown-it/markdown-it-deflist.git @license MIT */
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).markdownitDeflist=e()}(this,(function(){"use strict";return function(t){const e=t.utils.isSpace;function n(t,e){let n=t.bMarks[e]+t.tShift[e];const i=t.eMarks[e];if(n>=i)return-1;const o=t.src.charCodeAt(n++);if(126!==o&&58!==o)return-1;const r=t.skipSpaces(n);return n===r||r>=i?-1:n}t.block.ruler.before("paragraph","deflist",(function(t,i,o,r){if(r)return!(t.ddIndent<0)&&n(t,i)>=0;let s=i+1;if(s>=o)return!1;if(t.isEmpty(s)&&(s++,s>=o))return!1;if(t.sCount[s]<t.blkIndent)return!1;let d=n(t,s);if(d<0)return!1;const l=t.tokens.length;let f=!0;const a=[i,0];t.push("dl_open","dl",1).map=a;let p=i,u=s;t:for(;;){let i=!1;t.push("dt_open","dt",1).map=[p,p];const r=t.push("inline","",0);for(r.map=[p,p],r.content=t.getLines(p,p+1,t.blkIndent,!1).trim(),r.children=[],t.push("dt_close","dt",-1);;){const r=[s,0];t.push("dd_open","dd",1).map=r;let l=d;const a=t.eMarks[u];let p=t.sCount[u]+d-(t.bMarks[u]+t.tShift[u]);for(;l<a;){const n=t.src.charCodeAt(l);if(!e(n))break;9===n?p+=4-p%4:p++,l++}d=l;const c=t.tight,k=t.ddIndent,b=t.blkIndent,h=t.tShift[u],m=t.sCount[u],g=t.parentType;if(t.blkIndent=t.ddIndent=t.sCount[u]+2,t.tShift[u]=d-t.bMarks[u],t.sCount[u]=p,t.tight=!0,t.parentType="deflist",t.md.block.tokenize(t,u,o,!0),t.tight&&!i||(f=!1),i=t.line-u>1&&t.isEmpty(t.line-1),t.tShift[u]=h,t.sCount[u]=m,t.tight=c,t.parentType=g,t.blkIndent=b,t.ddIndent=k,t.push("dd_close","dd",-1),r[1]=s=t.line,s>=o)break t;if(t.sCount[s]<t.blkIndent)break t;if(d=n(t,s),d<0)break;u=s}if(s>=o)break;if(p=s,t.isEmpty(p))break;if(t.sCount[p]<t.blkIndent)break;if(u=p+1,u>=o)break;if(t.isEmpty(u)&&u++,u>=o)break;if(t.sCount[u]<t.blkIndent)break;if(d=n(t,u),d<0)break}return t.push("dl_close","dl",-1),a[1]=s,t.line=s,f&&function(t,e){const n=t.level+2;for(let i=e+2,o=t.tokens.length-2;i<o;i++)t.tokens[i].level===n&&"paragraph_open"===t.tokens[i].type&&(t.tokens[i+2].hidden=!0,t.tokens[i].hidden=!0,i+=2)}(t,l),!0}),{alt:["paragraph","reference","blockquote"]})}}));

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
/*! markdown-it-ins 3.0.1 https://github.com/markdown-it/markdown-it-mark @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitIns=n()}(this,(function(){"use strict";return function(e){function n(e,n){var t,o,s,i,r,l=[],f=n.length;for(t=0;t<f;t++)43===(s=n[t]).marker&&-1!==s.end&&(i=n[s.end],(r=e.tokens[s.token]).type="ins_open",r.tag="ins",r.nesting=1,r.markup="++",r.content="",(r=e.tokens[i.token]).type="ins_close",r.tag="ins",r.nesting=-1,r.markup="++",r.content="","text"===e.tokens[i.token-1].type&&"+"===e.tokens[i.token-1].content&&l.push(i.token-1));for(;l.length;){for(o=(t=l.pop())+1;o<e.tokens.length&&"ins_close"===e.tokens[o].type;)o++;t!==--o&&(r=e.tokens[o],e.tokens[o]=e.tokens[t],e.tokens[t]=r)}}e.inline.ruler.before("emphasis","ins",(function(e,n){var t,o,s,i,r=e.pos,l=e.src.charCodeAt(r);if(n)return!1;if(43!==l)return!1;if(s=(o=e.scanDelims(e.pos,!0)).length,i=String.fromCharCode(l),s<2)return!1;for(s%2&&(e.push("text","",0).content=i,s--),t=0;t<s;t+=2)e.push("text","",0).content=i+i,(o.can_open||o.can_close)&&e.delimiters.push({marker:l,length:0,jump:t/2,token:e.tokens.length-1,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0})),e.inline.ruler2.before("emphasis","ins",(function(e){var t,o=e.tokens_meta,s=(e.tokens_meta||[]).length;for(n(e,e.delimiters),t=0;t<s;t++)o[t]&&o[t].delimiters&&n(e,o[t].delimiters)}))}}));
/*! markdown-it-ins 4.0.0 https://github.com/markdown-it/markdown-it-ins @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitIns=n()}(this,(function(){"use strict";return function(e){function n(e,n){let t;const o=[],s=n.length;for(let i=0;i<s;i++){const s=n[i];if(43!==s.marker)continue;if(-1===s.end)continue;const r=n[s.end];t=e.tokens[s.token],t.type="ins_open",t.tag="ins",t.nesting=1,t.markup="++",t.content="",t=e.tokens[r.token],t.type="ins_close",t.tag="ins",t.nesting=-1,t.markup="++",t.content="","text"===e.tokens[r.token-1].type&&"+"===e.tokens[r.token-1].content&&o.push(r.token-1)}for(;o.length;){const n=o.pop();let s=n+1;for(;s<e.tokens.length&&"ins_close"===e.tokens[s].type;)s++;s--,n!==s&&(t=e.tokens[s],e.tokens[s]=e.tokens[n],e.tokens[n]=t)}}e.inline.ruler.before("emphasis","ins",(function(e,n){const t=e.pos,o=e.src.charCodeAt(t);if(n)return!1;if(43!==o)return!1;const s=e.scanDelims(e.pos,!0);let i=s.length;const r=String.fromCharCode(o);if(i<2)return!1;if(i%2){e.push("text","",0).content=r,i--}for(let n=0;n<i;n+=2){e.push("text","",0).content=r+r,(s.can_open||s.can_close)&&e.delimiters.push({marker:o,length:0,jump:n/2,token:e.tokens.length-1,end:-1,open:s.can_open,close:s.can_close})}return e.pos+=s.length,!0})),e.inline.ruler2.before("emphasis","ins",(function(e){const t=e.tokens_meta,o=(e.tokens_meta||[]).length;n(e,e.delimiters);for(let s=0;s<o;s++)t[s]&&t[s].delimiters&&n(e,t[s].delimiters)}))}}));

View File

@@ -1,2 +1,2 @@
/*! markdown-it-mark 3.0.1 https://github.com/markdown-it/markdown-it-mark @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitMark=n()}(this,(function(){"use strict";return function(e){function n(e,n){var t,o,r,s,i,a=[],k=n.length;for(t=0;t<k;t++)61===(r=n[t]).marker&&-1!==r.end&&(s=n[r.end],(i=e.tokens[r.token]).type="mark_open",i.tag="mark",i.nesting=1,i.markup="==",i.content="",(i=e.tokens[s.token]).type="mark_close",i.tag="mark",i.nesting=-1,i.markup="==",i.content="","text"===e.tokens[s.token-1].type&&"="===e.tokens[s.token-1].content&&a.push(s.token-1));for(;a.length;){for(o=(t=a.pop())+1;o<e.tokens.length&&"mark_close"===e.tokens[o].type;)o++;t!==--o&&(i=e.tokens[o],e.tokens[o]=e.tokens[t],e.tokens[t]=i)}}e.inline.ruler.before("emphasis","mark",(function(e,n){var t,o,r,s,i=e.pos,a=e.src.charCodeAt(i);if(n)return!1;if(61!==a)return!1;if(r=(o=e.scanDelims(e.pos,!0)).length,s=String.fromCharCode(a),r<2)return!1;for(r%2&&(e.push("text","",0).content=s,r--),t=0;t<r;t+=2)e.push("text","",0).content=s+s,(o.can_open||o.can_close)&&e.delimiters.push({marker:a,length:0,jump:t/2,token:e.tokens.length-1,end:-1,open:o.can_open,close:o.can_close});return e.pos+=o.length,!0})),e.inline.ruler2.before("emphasis","mark",(function(e){var t,o=e.tokens_meta,r=(e.tokens_meta||[]).length;for(n(e,e.delimiters),t=0;t<r;t++)o[t]&&o[t].delimiters&&n(e,o[t].delimiters)}))}}));
/*! markdown-it-mark 4.0.0 https://github.com/markdown-it/markdown-it-mark @license MIT */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitMark=n()}(this,(function(){"use strict";return function(e){function n(e,n){const t=[],o=n.length;for(let s=0;s<o;s++){const o=n[s];if(61!==o.marker)continue;if(-1===o.end)continue;const r=n[o.end],i=e.tokens[o.token];i.type="mark_open",i.tag="mark",i.nesting=1,i.markup="==",i.content="";const c=e.tokens[r.token];c.type="mark_close",c.tag="mark",c.nesting=-1,c.markup="==",c.content="","text"===e.tokens[r.token-1].type&&"="===e.tokens[r.token-1].content&&t.push(r.token-1)}for(;t.length;){const n=t.pop();let o=n+1;for(;o<e.tokens.length&&"mark_close"===e.tokens[o].type;)o++;if(o--,n!==o){const t=e.tokens[o];e.tokens[o]=e.tokens[n],e.tokens[n]=t}}}e.inline.ruler.before("emphasis","mark",(function(e,n){const t=e.pos,o=e.src.charCodeAt(t);if(n)return!1;if(61!==o)return!1;const s=e.scanDelims(e.pos,!0);let r=s.length;const i=String.fromCharCode(o);if(r<2)return!1;if(r%2){e.push("text","",0).content=i,r--}for(let n=0;n<r;n+=2){e.push("text","",0).content=i+i,(s.can_open||s.can_close)&&e.delimiters.push({marker:o,length:0,jump:n/2,token:e.tokens.length-1,end:-1,open:s.can_open,close:s.can_close})}return e.pos+=s.length,!0})),e.inline.ruler2.before("emphasis","mark",(function(e){let t;const o=e.tokens_meta,s=(e.tokens_meta||[]).length;for(n(e,e.delimiters),t=0;t<s;t++)o[t]&&o[t].delimiters&&n(e,o[t].delimiters)}))}}));

View File

@@ -1,2 +1,2 @@
/*! markdown-it-sub 1.0.0 https://github.com//markdown-it/markdown-it-sub @license MIT */
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.markdownitSub=e()}}(function(){return function e(r,o,n){function t(i,u){if(!o[i]){if(!r[i]){var f="function"==typeof require&&require;if(!u&&f)return f(i,!0);if(s)return s(i,!0);var p=new Error("Cannot find module '"+i+"'");throw p.code="MODULE_NOT_FOUND",p}var a=o[i]={exports:{}};r[i][0].call(a.exports,function(e){var o=r[i][1][e];return t(o?o:e)},a,a.exports,e,r,o,n)}return o[i].exports}for(var s="function"==typeof require&&require,i=0;i<n.length;i++)t(n[i]);return t}({1:[function(e,r){"use strict";function o(e,r){var o,t,s,i=e.posMax,u=e.pos;if(126!==e.src.charCodeAt(u))return!1;if(r)return!1;if(u+2>=i)return!1;for(e.pos=u+1;e.pos<i;){if(126===e.src.charCodeAt(e.pos)){o=!0;break}e.md.inline.skipToken(e)}return o&&u+1!==e.pos?(t=e.src.slice(u+1,e.pos),t.match(/(^|[^\\])(\\\\)*\s/)?(e.pos=u,!1):(e.posMax=e.pos,e.pos=u+1,s=e.push("sub_open","sub",1),s.markup="~",s=e.push("text","",0),s.content=t.replace(n,"$1"),s=e.push("sub_close","sub",-1),s.markup="~",e.pos=e.posMax+1,e.posMax=i,!0)):(e.pos=u,!1)}var n=/\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;r.exports=function(e){e.inline.ruler.after("emphasis","sub",o)}},{}]},{},[1])(1)});
/*! markdown-it-sub 2.0.0 https://github.com/markdown-it/markdown-it-sub @license MIT */
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitSub=s()}(this,(function(){"use strict";const e=/\\([ \\!"#$%&'()*+,./:;<=>?@[\]^_`{|}~-])/g;function s(s,o){const n=s.posMax,t=s.pos;if(126!==s.src.charCodeAt(t))return!1;if(o)return!1;if(t+2>=n)return!1;s.pos=t+1;let r=!1;for(;s.pos<n;){if(126===s.src.charCodeAt(s.pos)){r=!0;break}s.md.inline.skipToken(s)}if(!r||t+1===s.pos)return s.pos=t,!1;const p=s.src.slice(t+1,s.pos);if(p.match(/(^|[^\\])(\\\\)*\s/))return s.pos=t,!1;s.posMax=s.pos,s.pos=t+1;s.push("sub_open","sub",1).markup="~";s.push("text","",0).content=p.replace(e,"$1");return s.push("sub_close","sub",-1).markup="~",s.pos=s.posMax+1,s.posMax=n,!0}return function(e){e.inline.ruler.after("emphasis","sub",s)}}));

View File

@@ -1,2 +1,2 @@
/*! markdown-it-sup 1.0.0 https://github.com//markdown-it/markdown-it-sup @license MIT */
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var r;r="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,r.markdownitSup=e()}}(function(){return function e(r,o,n){function t(i,p){if(!o[i]){if(!r[i]){var u="function"==typeof require&&require;if(!p&&u)return u(i,!0);if(s)return s(i,!0);var f=new Error("Cannot find module '"+i+"'");throw f.code="MODULE_NOT_FOUND",f}var a=o[i]={exports:{}};r[i][0].call(a.exports,function(e){var o=r[i][1][e];return t(o?o:e)},a,a.exports,e,r,o,n)}return o[i].exports}for(var s="function"==typeof require&&require,i=0;i<n.length;i++)t(n[i]);return t}({1:[function(e,r){"use strict";function o(e,r){var o,t,s,i=e.posMax,p=e.pos;if(94!==e.src.charCodeAt(p))return!1;if(r)return!1;if(p+2>=i)return!1;for(e.pos=p+1;e.pos<i;){if(94===e.src.charCodeAt(e.pos)){o=!0;break}e.md.inline.skipToken(e)}return o&&p+1!==e.pos?(t=e.src.slice(p+1,e.pos),t.match(/(^|[^\\])(\\\\)*\s/)?(e.pos=p,!1):(e.posMax=e.pos,e.pos=p+1,s=e.push("sup_open","sup",1),s.markup="^",s=e.push("text","",0),s.content=t.replace(n,"$1"),s=e.push("sup_close","sup",-1),s.markup="^",e.pos=e.posMax+1,e.posMax=i,!0)):(e.pos=p,!1)}var n=/\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;r.exports=function(e){e.inline.ruler.after("emphasis","sup",o)}},{}]},{},[1])(1)});
/*! markdown-it-sup 2.0.0 https://github.com/markdown-it/markdown-it-sup @license MIT */
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownitSup=s()}(this,(function(){"use strict";const e=/\\([ \\!"#$%&'()*+,./:;<=>?@[\]^_`{|}~-])/g;function s(s,o){const n=s.posMax,p=s.pos;if(94!==s.src.charCodeAt(p))return!1;if(o)return!1;if(p+2>=n)return!1;s.pos=p+1;let t=!1;for(;s.pos<n;){if(94===s.src.charCodeAt(s.pos)){t=!0;break}s.md.inline.skipToken(s)}if(!t||p+1===s.pos)return s.pos=p,!1;const r=s.src.slice(p+1,s.pos);if(r.match(/(^|[^\\])(\\\\)*\s/))return s.pos=p,!1;s.posMax=s.pos,s.pos=p+1;s.push("sup_open","sup",1).markup="^";s.push("text","",0).content=r.replace(e,"$1");return s.push("sup_close","sup",-1).markup="^",s.pos=s.posMax+1,s.posMax=n,!0}return function(e){e.inline.ruler.after("emphasis","sup",s)}}));

File diff suppressed because one or more lines are too long

View File

@@ -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);
}
});
}

View File

@@ -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;