1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-14 14:09:51 +00:00

Compare commits

..

3 Commits

Author SHA1 Message Date
Jeremy Ruston
1130674d5c Fixed minimal test case 2025-04-05 13:11:58 +01:00
Jeremy Ruston
bf335b53e9 Revert "Initial Commit"
Oops

This reverts commit 5803b5d421.
2025-04-05 12:53:15 +01:00
Jeremy Ruston
5803b5d421 Initial Commit
The output in HelloThere is xxxx .... xxxx .... xxxx .... xxxx .... xxxx .... xxxx .... xxxx .... xxxx .... and yet the test passes
2025-04-05 12:41:54 +01:00
95 changed files with 293 additions and 1254 deletions

View File

@@ -105,34 +105,20 @@ node $TW5_BUILD_TIDDLYWIKI \
fi
# /index.html Main site
# /external-(version).html External core version of main site
# /favicon.ico Favicon for main site
node $TW5_BUILD_TIDDLYWIKI \
$TW5_BUILD_MAIN_EDITION \
--version \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--build favicon index external-js \
|| exit 1
# /static.html Static rendering of default tiddlers
# /alltiddlers.html Static rendering of all tiddlers
# /static/* Static single tiddlers
# /static/static.css Static stylesheet
# /static/favicon.ico Favicon for static pages
# Conditionally build static files if $TW5_BUILD_STATIC variable is not set or is set to 0
if [ -z "$TW5_BUILD_STATIC" ] || [ "$TW5_BUILD_STATIC" = "0" ]; then
node $TW5_BUILD_TIDDLYWIKI \
$TW5_BUILD_MAIN_EDITION \
--version \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--build static \
--build favicon static index \
|| exit 1
fi
# /empty.html Empty
# /empty.hta For Internet Explorer
@@ -169,7 +155,7 @@ node $TW5_BUILD_TIDDLYWIKI \
node $TW5_BUILD_TIDDLYWIKI \
./editions/tour \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js tour.html text/plain \
--rendertiddler $:/core/save/all tour.html text/plain \
|| exit 1
# /share.html Custom edition for sharing via the URL
@@ -203,15 +189,12 @@ node $TW5_BUILD_TIDDLYWIKI \
#
######################################################
# Conditionally build editions if $TW5_BUILD_EDITIONS variable is not set or is set to 0
if [ -z "$TW5_BUILD_EDITIONS" ] || [ "$TW5_BUILD_EDITIONS" = "0" ]; then
# /editions/xlsx-utils/index.html xlsx-utils edition
node $TW5_BUILD_TIDDLYWIKI \
./editions/xlsx-utils \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/xlsx-utils/ \
--build external \
--build index \
|| exit 1
# /editions/resumebuilder/index.html Resume builder edition
@@ -227,7 +210,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/text-slicer \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/text-slicer/ \
--build external \
--build index \
|| exit 1
# /editions/translators/index.html Translators edition
@@ -259,7 +242,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/tw5.com-docs \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT/editions/tw5.com-docs/ \
--build external \
--build index \
|| exit 1
# /editions/twitter-archivist/index.html Twitter Archivist edition
@@ -270,25 +253,19 @@ node $TW5_BUILD_TIDDLYWIKI \
--build index \
|| exit 1
fi
######################################################
#
# Plugin demos
#
######################################################
# Conditionally build plugin demos if $TW5_BUILD_PLUGIN_DEMOS variable is not set
if [ -z "$TW5_BUILD_PLUGIN_DEMOS" ] || [ "$TW5_BUILD_PLUGIN_DEMOS" = "0" ]; then
# /plugins/tiddlywiki/innerwiki/index.html Demo wiki with Innerwiki plugin
node $TW5_BUILD_TIDDLYWIKI \
./editions/innerwikidemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/innerwiki/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/innerwiki/index.html text/plain \
|| exit 1
# /plugins/tiddlywiki/dynaview/index.html Demo wiki with DynaView plugin
@@ -298,7 +275,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/dynaviewdemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/dynaview/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/dynaview/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/dynaview/empty.html text/plain \
|| exit 1
@@ -312,7 +289,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/katexdemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/katex/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/katex/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|| exit 1
@@ -342,7 +319,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/codemirrordemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/codemirror/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/codemirror/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/codemirror/empty.html text/plain \
|| exit 1
@@ -352,7 +329,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/markdowndemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/markdown/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/markdown/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/markdown/empty.html text/plain \
|| exit 1
@@ -362,7 +339,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/classicparserdemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/tw2parser/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/tw2parser/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tw2parser/empty.html text/plain \
|| exit 1
@@ -372,7 +349,7 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/highlightdemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/highlight/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/highlight/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|| exit 1
@@ -382,21 +359,16 @@ node $TW5_BUILD_TIDDLYWIKI \
./editions/geospatialdemo \
--load $TW5_BUILD_OUTPUT/build.tid \
--output $TW5_BUILD_OUTPUT \
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/geospatial/index.html text/plain \
--rendertiddler $:/core/save/all plugins/tiddlywiki/geospatial/index.html text/plain \
--rendertiddler $:/core/save/empty plugins/tiddlywiki/geospatial/empty.html text/plain \
|| exit 1
fi
######################################################
#
# Language editions
#
######################################################
# Conditionally build language editions if $TW5_BUILD_LANGUAGE_DEMOS variable is not set
if [ -z "$TW5_BUILD_LANGUAGE_DEMOS" ] || [ "$TW5_BUILD_LANGUAGE_DEMOS" = "0" ]; then
# Delete any existing static content
rm -rf $TW5_BUILD_OUTPUT/languages/de-AT/static/*
@@ -480,17 +452,12 @@ node $TW5_BUILD_TIDDLYWIKI \
--build empty index \
|| exit 1
fi
######################################################
#
# Plugin library
#
######################################################
# Conditionally build plugin library if $TW5_BUILD_PLUGIN_LIBRARY variable is not set
if [ -z "$TW5_BUILD_PLUGIN_LIBRARY" ] || [ "$TW5_BUILD_PLUGIN_LIBRARY" = "0" ]; then
node $TW5_BUILD_TIDDLYWIKI \
./editions/pluginlibrary \
--load $TW5_BUILD_OUTPUT/build.tid \
@@ -498,8 +465,6 @@ node $TW5_BUILD_TIDDLYWIKI \
--build library\
|| exit 1
fi
# Delete the temporary build tiddler
rm $TW5_BUILD_OUTPUT/build.tid || exit 1

View File

@@ -2000,7 +2000,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
var value = tiddler[name];
switch(fieldInfo.source) {
case "subdirectories":
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
value = path.relative(rootPath, filename).split(path.sep).slice(0, -1);
break;
case "filepath":
value = path.relative(rootPath, filename).split(path.sep).join('/');
@@ -2021,10 +2021,10 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
value = path.extname(filename);
break;
case "created":
value = $tw.utils.stringifyDate(new Date(fs.statSync(pathname).birthtime));
value = new Date(fs.statSync(pathname).birthtime);
break;
case "modified":
value = $tw.utils.stringifyDate(new Date(fs.statSync(pathname).mtime));
value = new Date(fs.statSync(pathname).mtime);
break;
}
if(fieldInfo.prefix) {
@@ -2732,15 +2732,14 @@ $tw.hooks.removeHook = function(hookName,definition) {
/*
Invoke the hook by key
*/
$tw.hooks.invokeHook = function(hookName, firstArgument /*, value,... */) {
if(Object.prototype.hasOwnProperty.call($tw.hooks.names,hookName)) {
var args = Array.prototype.slice.call(arguments,1);
$tw.hooks.invokeHook = function(hookName /*, value,... */) {
var args = Array.prototype.slice.call(arguments,1);
if($tw.utils.hop($tw.hooks.names,hookName)) {
for(var i = 0; i < $tw.hooks.names[hookName].length; i++) {
args[0] = $tw.hooks.names[hookName][i].apply(null,args);
}
return args[0];
}
return firstArgument;
return args[0];
};
/////////////////////////// Main boot function to decrypt tiddlers and then startup

View File

@@ -4,12 +4,12 @@ _canonical_uri: The full URI of an external image tiddler
author: Name of the author of a plugin
bag: The name of the bag from which a tiddler came
caption: The text to be displayed on a tab or button
class: The CSS class applied to a tiddler when rendering it. Also used for Modals
class: The CSS class applied to a tiddler when rendering it - see [[Custom styles by user-class]]. Also used for [[Modals]]
code-body: The view template will display the tiddler as code if set to ''yes''
color: The CSS color value associated with a tiddler
component: The name of the component responsible for an alert tiddler
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
core-version: For a plugin, indicates what version of TiddlyWiki with which it is compatible
current-tiddler: Used to cache the top tiddler in a history list
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
created: The date a tiddler was created
creator: The name of the person who created a tiddler
dependents: For a plugin, lists the dependent plugin titles

View File

@@ -3,9 +3,7 @@ title: $:/language/Search/
DefaultResults/Caption: List
Filter/Caption: Filter
Filter/Hint: Search via a [[filter expression|https://tiddlywiki.com/static/Filters.html]]
Filter/Placeholder: Filter expression
Filter/Matches: //<small><<resultCount>> matches</small>//
Filter/FilterResults/Results/Caption: Results
Matches: //<small><<resultCount>> matches</small>//
Matches/All: All matches:
Matches/NoMatch: //No match//

View File

@@ -220,25 +220,13 @@ exports.filterTiddlers = function(filterString,widget,source) {
Compile a filter into a function with the signature fn(source,widget) where:
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
widget: an optional widget node for retrieving the current tiddler etc.
Parameters:
filterString: the filter string to compile
options: includes:
wrappers: a hashmap of wrapper functions to apply to the compiled filter function
*/
exports.compileFilter = function(filterString,options) {
options = options || {};
var self = this;
var wrappers = options.wrappers || {};
// Invoke the hook to allow the filter to be inspected
wrappers = $tw.hooks.invokeHook("th-filter-evaluation",filterString,wrappers) || wrappers;
// Get the result from the cache if we can
exports.compileFilter = function(filterString) {
if(!this.filterCache) {
this.filterCache = Object.create(null);
this.filterCacheCount = 0;
}
if(this.filterCache[filterString] !== undefined && !wrappers.prefix && !wrappers.operation && !wrappers.operator && !wrappers.start && !wrappers.done) {
if(this.filterCache[filterString] !== undefined) {
return this.filterCache[filterString];
}
var filterParseTree;
@@ -247,14 +235,7 @@ exports.compileFilter = function(filterString,options) {
} catch(e) {
// We do not cache this result, so it adjusts along with localization changes
return function(source,widget) {
if(wrappers.start) {
wrappers.start(source,widget);
}
var resultsArray = [$tw.language.getString("Error/Filter") + ": " + e];
if(wrappers.done) {
wrappers.done(resultsArray);
}
return resultsArray;
return [$tw.language.getString("Error/Filter") + ": " + e];
};
}
// Get the hashmap of filter operator functions
@@ -268,64 +249,52 @@ exports.compileFilter = function(filterString,options) {
var operationSubFunction = function(source,widget) {
var accumulator = source,
results = [],
currTiddlerTitle = widget && widget.getVariable("currentTiddler"),
handleOperation = function() {
$tw.utils.each(operation.operators,function(operator) {
var operands = [],
operatorName,operatorFunction;
if(!operator.operator) {
// Use the "title" operator if no operator is specified
operatorName = "title";
} else if(!filterOperators[operator.operator]) {
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
operatorName = "[unknown]";
} else {
// Use the operator function
operatorName = operator.operator;
}
operatorFunction = filterOperators[operatorName];
$tw.utils.each(operator.operands,function(operand) {
if(operand.indirect) {
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
} else if(operand.variable) {
var varTree = $tw.utils.parseFilterVariable(operand.text);
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
} else {
operand.value = operand.text;
}
operands.push(operand.value);
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
$tw.utils.each(operation.operators,function(operator) {
var operands = [],
operatorFunction;
if(!operator.operator) {
// Use the "title" operator if no operator is specified
operatorFunction = filterOperators.title;
} else if(!filterOperators[operator.operator]) {
// Unknown operators treated as "[unknown]" - at run time we can distinguish between a custom operator and falling back to the default "field" operator
operatorFunction = filterOperators["[unknown]"];
} else {
// Use the operator function
operatorFunction = filterOperators[operator.operator];
}
$tw.utils.each(operator.operands,function(operand) {
if(operand.indirect) {
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
} else if(operand.variable) {
var varTree = $tw.utils.parseFilterVariable(operand.text);
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
} else {
operand.value = operand.text;
}
operands.push(operand.value);
});
// Invoke the appropriate filteroperator module
results = operatorFunction(accumulator,{
operator: operator.operator,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
// Wrap the filter operator module if required
if(wrappers.operator) {
operatorFunction = wrappers.operator.bind(self,operatorFunction);
}
// Invoke the appropriate filteroperator module
results = operatorFunction(accumulator,{
parseTree: operator,
operator: operator.operator,
operatorName: operatorName,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
if($tw.utils.isArray(results)) {
accumulator = self.makeTiddlerIterator(results);
} else {
accumulator = results;
}
});
};
if(wrappers.operation) {
handleOperation = wrappers.operation.bind(self,handleOperation,operation);
}
handleOperation();
if($tw.utils.isArray(results)) {
if($tw.utils.isArray(results)) {
accumulator = self.makeTiddlerIterator(results);
} else {
accumulator = results;
}
});
if($tw.utils.isArray(results)) {
return results;
} else {
var resultArray = [];
@@ -338,45 +307,27 @@ exports.compileFilter = function(filterString,options) {
var filterRunPrefixes = self.getFilterRunPrefixes();
// Wrap the operator functions in a wrapper function that depends on the prefix
operationFunctions.push((function() {
var prefixName;
var options = {wiki: self, suffixes: operation.suffixes || []};
switch(operation.prefix || "") {
case "": // No prefix means that the operation is unioned into the result
prefixName = "or";
break;
return filterRunPrefixes["or"](operationSubFunction, options);
case "=": // The results of the operation are pushed into the result without deduplication
prefixName = "all";
break;
return filterRunPrefixes["all"](operationSubFunction, options);
case "-": // The results of this operation are removed from the main result
prefixName = "except";
break;
return filterRunPrefixes["except"](operationSubFunction, options);
case "+": // This operation is applied to the main results so far
prefixName = "and";
break;
return filterRunPrefixes["and"](operationSubFunction, options);
case "~": // This operation is unioned into the result only if the main result so far is empty
prefixName = "else";
break;
default:
prefixName = operation.namedPrefix;
break;
}
if(prefixName && filterRunPrefixes[prefixName]) {
var options = {
wiki: self,
suffixes: operation.suffixes || [],
prefixName: prefixName,
prefix: operation.prefix
},
filterRunPrefixFunction = filterRunPrefixes[prefixName];
// Wrap the filter operator module if required
if(wrappers.prefix) {
filterRunPrefixFunction = wrappers.prefix.bind(self,filterRunPrefixFunction);
}
return filterRunPrefixFunction(operationSubFunction,options);
} else {
return function(results,source,widget) {
results.clear();
results.push($tw.language.getString("Error/FilterRunPrefix"));
};
return filterRunPrefixes["else"](operationSubFunction, options);
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
} else {
return function(results,source,widget) {
results.clear();
results.push($tw.language.getString("Error/FilterRunPrefix"));
};
}
}
})());
});
@@ -390,9 +341,6 @@ exports.compileFilter = function(filterString,options) {
if(!widget) {
widget = $tw.rootWidget;
}
if(wrappers.start) {
wrappers.start(source,widget);
}
var results = new $tw.utils.LinkedList();
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
@@ -403,11 +351,7 @@ exports.compileFilter = function(filterString,options) {
results.push("/**-- Excessive filter recursion --**/");
}
self.filterRecursionCount = self.filterRecursionCount - 1;
var resultsArray = results.toArray();
if(wrappers.done) {
wrappers.done(resultsArray);
}
return resultsArray;
return results.toArray();
});
if(this.filterCacheCount >= 2000) {
// To prevent memory leak, we maintain an upper limit for cache size.
@@ -416,9 +360,7 @@ exports.compileFilter = function(filterString,options) {
this.filterCache = Object.create(null);
this.filterCacheCount = 0;
}
if(!wrappers.prefix && !wrappers.operator) {
this.filterCache[filterString] = fnMeasured;
this.filterCacheCount++;
}
this.filterCache[filterString] = fnMeasured;
this.filterCacheCount++;
return fnMeasured;
};

View File

@@ -6,6 +6,7 @@ module-type: filteroperator
Filter operator for returning all the backtranscludes from a tiddler
\*/
(function(){
"use strict";
/*
@@ -18,3 +19,5 @@ exports.backtranscludes = function(source,operator,options) {
});
return results.makeTiddlerIterator(options.wiki);
};
})();

View File

@@ -6,6 +6,7 @@ module-type: filteroperator
Filter operator for returning all the transcludes from a tiddler
\*/
(function(){
"use strict";
/*
@@ -18,3 +19,5 @@ exports.transcludes = function(source,operator,options) {
});
return results.makeTiddlerIterator(options.wiki);
};
})();

View File

@@ -10,6 +10,7 @@ This is a <%if [{something}] %>Elephant<%elseif [{else}] %>Pelican<%else%>Crocod
```
\*/
(function(){
"use strict";
exports.name = "conditional";
@@ -112,3 +113,5 @@ exports.parseIfClause = function(filterCondition) {
// Return the parse tree node
return [listWidget];
};
})();

View File

@@ -6,6 +6,8 @@ module-type: utils
Custom errors for TiddlyWiki.
\*/
(function(){
function TranscludeRecursionError() {
Error.apply(this,arguments);
this.signatures = Object.create(null);
@@ -17,3 +19,5 @@ TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH = 1000;
TranscludeRecursionError.prototype = Object.create(Error);
exports.TranscludeRecursionError = TranscludeRecursionError;
})();

View File

@@ -6,6 +6,7 @@ module-type: utils
Utilities for working with the TiddlyWiki repository file structure
\*/
(function(){
"use strict";
/*
@@ -44,3 +45,5 @@ exports.getAllPlugins = function(options) {
$tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.languagesEnvVar),collectPlugins);
return tiddlers;
};
})();

View File

@@ -6,6 +6,7 @@ module-type: widget
Widget to dynamically represent one or more tiddlers
\*/
(function(){
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
@@ -186,3 +187,5 @@ function hasPayloadChanged(a,b) {
}
exports.data = DataWidget;
})();

View File

@@ -6,6 +6,7 @@ module-type: widget
Widget to display a test case
\*/
(function(){
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
@@ -159,3 +160,5 @@ TestCaseWidget.prototype.refresh = function(changedTiddlers) {
};
exports["testcase"] = TestCaseWidget;
})();

View File

@@ -34,11 +34,39 @@ caption: {{$:/language/Search/Filter/Caption}}
</$list>
\end
\procedure input-accept-actions()
\whitespace trim
<$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]">
<$list-empty>
<$list filter="[<tiddler>get[text]!is[missing]] :else[<tiddler>get[text]is[shadow]]">
<$action-navigate $to={{{ [<tiddler>get[text]] }}}/>
</$list>
<$/list-empty>
<$action-navigate $to={{{ [<tiddler>get[text]] }}}/>
</$list>
\end
\procedure input-accept-variant-actions()
\whitespace trim
<$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]">
<$list-empty>
<$list filter="[<tiddler>get[text]!is[missing]] :else[<tiddler>get[text]is[shadow]]">
<$list filter="[<__tiddler__>get[text]minlength[1]]">
<$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<tiddler>get[text]] }}}/>
</$list>
</$list>
</$list-empty>
<$list filter="[<tiddler>get[text]minlength[1]]">
<$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<tiddler>get[text]] }}}/>
</$list>
</$list>
\end
\whitespace trim
<<lingo Filter/Hint>>
<div class="tc-search tc-advanced-search tc-edit-max-width">
<div class="tc-search tc-advanced-search">
<$keyboard key="((input-tab-right))" actions=<<set-next-input-tab>> class="tc-small-gap-right">
<$keyboard key="((input-tab-left))" actions=<<set-previous-input-tab>>>
<$transclude $variable="keyboard-driven-input"
@@ -47,16 +75,13 @@ caption: {{$:/language/Search/Filter/Caption}}
refreshTitle="$:/temp/advancedsearch/refresh"
selectionStateTitle="$:/temp/advancedsearch/selected-item"
type="search"
tag="textarea"
tag="input"
focus={{$:/config/Search/AutoFocus}}
configTiddlerFilter="[[$:/temp/advancedsearch]]"
firstSearchFilterField="text"
inputAcceptActions=""
inputAcceptVariantActions=""
inputAcceptActions=<<input-accept-actions>>
inputAcceptVariantActions=<<input-accept-variant-actions>>
inputCancelActions=<<cancel-search-actions>>
minHeight="2em"
autoHeight="yes"
placeholder={{$:/language/Search/Filter/Placeholder}}
/>
</$keyboard>
</$keyboard>
@@ -65,18 +90,13 @@ caption: {{$:/language/Search/Filter/Caption}}
</$list>
</div>
<%if [{$:/temp/advancedsearch}trim[]!match[]] %>
<div class="tc-search-results">
<%if [all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]count[]compare:number:gt[1]] %>
<$macrocall
$name="tabs"
tabsList="[all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]]"
default="$:/core/ui/AdvancedSearch/Filter/FilterResults/Results"
/>
<%else%>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/AdvancedSearch/FilterResults]!has[draft.of]]">
<$transclude/>
</$list>
<%endif%>
</div>
<%endif%>
<$reveal state="$:/temp/advancedsearch" type="nomatch" text="" tag="div" class="tc-search-results">
<$set name="resultCount" value="<$count filter={{$:/temp/advancedsearch}}/>">
<p><<lingo Filter/Matches>></p>
<$list filter={{$:/temp/advancedsearch}}>
<span class={{{[<currentTiddler>addsuffix[-primaryList]] -[[$:/temp/advancedsearch/selected-item]get[text]] :and[then[]else[tc-list-item-selected]] }}}>
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
</span>
</$list>
</$set>
</$reveal>

View File

@@ -1,13 +0,0 @@
title: $:/core/ui/AdvancedSearch/Filter/FilterResults/Results
tags: $:/tags/AdvancedSearch/FilterResults
caption: {{$:/language/Search/Filter/FilterResults/Results/Caption}}
\procedure lingo-base() $:/language/Search/
<$set name="resultCount" value="<$count filter={{$:/temp/advancedsearch}}/>">
<p><<lingo Filter/Matches>></p>
<$list filter={{$:/temp/advancedsearch}}>
<span class={{{[<currentTiddler>addsuffix[-primaryList]] -[[$:/temp/advancedsearch/selected-item]get[text]] :and[then[]else[tc-list-item-selected]] }}}>
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
</span>
</$list>
</$set>

View File

@@ -37,7 +37,7 @@ caption: {{$:/language/Search/Standard/Caption}}
inputCancelActions=<<cancel-search-actions>>
inputAcceptActions=<<input-accept-actions>>
inputAcceptVariantActions=<<input-accept-variant-actions>>
configTiddlerFilter="[[$:/state/advancedsearch/standard/currentTab]!is[missing]get[text]] :else[{$:/config/SearchResults/Default}]"
configTiddlerFilter="[[$:/state/search/currentTab]!is[missing]get[text]] :else[{$:/config/SearchResults/Default}]"
filterMinLength={{$:/config/Search/MinLength}}/>
</$keyboard>
</$keyboard>

View File

@@ -12,7 +12,7 @@ Export the TiddlyWiki core JavaScript code for running with external JavaScript:
tooltip="Export the TiddlyWiki core code for running with external JavaScript"
aria-label="export TiddlyWiki core"
class="tc-btn-big-green">
<$action-sendmessage $message='tm-download-file' $param='$:/core/templates/tiddlywiki5.js' filename=<<jsFileName>> type="application/javascript"/>
<$action-sendmessage $message='tm-download-file' $param='$:/core/templates/tiddlywiki5.js' filename=<<jsFileName>>/>
{{$:/core/images/download-button}}
<span class="tc-tiny-gap-left">
Download TiddlyWiki core

View File

@@ -12,7 +12,7 @@ element, and right-click its `src` URI. Save the link as ''$(jsFileName)$''</p>
Export the ~TiddlyWiki core ~JavaScript code for running with external ~JavaScript:
<$button tooltip="Export the ~TiddlyWiki core code for running with external ~JavaScript" aria-label="export TiddlyWiki core" class="tc-btn-big-green">
<$list filter="[[$:/boot/boot.js]is[missing]]" variable="ignore" emptyMessage="""<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/tiddlywiki5.js" filename=<<jsFileName>> type="application/javascript"/>""" >
<$list filter="[[$:/boot/boot.js]is[missing]]" variable="ignore" emptyMessage="""<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/tiddlywiki5.js" filename=<<jsFileName>>/>""" >
<$action-setfield $tiddler=<<qualify "$:/temp/alert">> text=<<noExportMsg>> subtitle="Export ~TiddllyWiki Core"/>
<$action-sendmessage $message="tm-modal" $param=<<qualify "$:/temp/alert">>/>
</$list>

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -11,9 +11,6 @@
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","classicparserdemo.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","classicparserdemo.html","text/plain"
]
"--rendertiddler","$:/core/save/all","classicparserdemo.html","text/plain"]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -22,9 +22,6 @@
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","codemirrordemo.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","codemirrordemo.html","text/plain"
]
"--rendertiddler","$:/core/save/all","codemirrordemo.html","text/plain"]
}
}

View File

@@ -28,4 +28,5 @@ Note that JavaScript macros work on both the client and the server, and so do no
!! Macro Behaviour
Macros are just used to return a chunk of wikitext for further processing. They should not make modifications to tiddlers in the wiki store. The reason is that you cannot control when the macro is called; it may be called repeatedly as part of refresh processing. So it is important that macros do not have any other side effects beyond generating their text.
Macros are just used to return a chunk of wikitext for further processing. They should not make modifications to tiddlers in the wiki store. The reason is that you cannott control when the macro is called; it may be called repeatedly as part of refresh processing. So it is important that macros do not have any other side effects beyond generating their text.

View File

@@ -34,11 +34,13 @@ Suppose we want to make a filter operator that returns every other tiddler from
We make a new tiddler, set its `type` and `module-type` appropriately, and begin writing the code:
```
(function(){
"use strict";
exports.everyother = function(source, operator, options) {
// TODO
}
})();
```
For the example filter syntax, our function will be called with
@@ -52,6 +54,7 @@ As is usually the case, we don't care about `operator.operator` here (since that
We could implement the operator by iterating over the input tiddlers and explicitly building a result array of titles:
```
(function(){
"use strict";
exports.everyother = function(source, operator, options) {
@@ -63,6 +66,7 @@ exports.everyother = function(source, operator, options) {
});
return result;
}
})();
```
That is, we supply a callback to `source` that negates `include` each time through (in order to grab every other result) and pushes the `title` of every other tiddler onto the result.
@@ -70,6 +74,7 @@ That is, we supply a callback to `source` that negates `include` each time throu
Alternatively, we can return our own iterator, by returning a function that accepts a similar callback and only calls it on every other tiddler:
```
(function(){
"use strict";
exports.everyother = function(source, operator, options) {
@@ -81,6 +86,7 @@ exports.everyother = function(source, operator, options) {
});
};
}
})();
```
Either way, we could interpret the `!` flag on the filter, if present, to mean that we want the //other// half of the tiddlers, by using it to set the initial value of `include`: `var include = operator.prefix !== "!";`

View File

@@ -40,7 +40,10 @@ module-type: startup
YOUR DISCRCRIPTION COMES HERE!
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false, exports: true */
"use strict";
// Export name and synchronous status
@@ -60,4 +63,6 @@ exports.startup = function() {
});
};
})();
```

View File

@@ -11,7 +11,10 @@ The wikitext parser subclassing mechanism makes it possible for custom parsers t
Here is an example of a subclass of the checkbox widget that adds logging to the event handler:
```js
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var WikiParser = require("$:/core/modules/parsers/wikiparser/wikiparser.js")["text/vnd.tiddlywiki"],
@@ -35,4 +38,5 @@ var MyCustomWikiParser = function(type,text,options) {
exports["text/vnd.my-custom-type"] = MyCustomWikiParser;
})();
```

View File

@@ -26,7 +26,10 @@ module-type: widget-subclass
Widget base class
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
exports.baseClass = "checkbox"; // Extend the <$checkbox> widget
@@ -47,4 +50,5 @@ exports.prototype.handleChangeEvent = function(event) {
console.log("Checkbox status:",this.inputDomNode.checked);
};
})();
```

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -9,9 +9,6 @@
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","index.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
]
"--rendertiddler","$:/core/save/all","index.html","text/plain"]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -15,9 +15,6 @@
"build": {
"index": [
"--render","$:/core/save/all","index.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
],
"favicon": [],
"static": [],
"empty": [],

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -16,9 +16,6 @@
"--render","$:/core/templates/static.template.html","static.html","text/plain",
"--render","$:/core/templates/alltiddlers.template.html","alltiddlers.html","text/plain",
"--render","[!is[system]]","[encodeuricomponent[]addprefix[static/]addsuffix[.html]]","text/plain","$:/core/templates/static.tiddler.html",
"--render","$:/core/templates/static.template.css","static/static.css","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","highlightdemo.html","text/plain"
]
"--render","$:/core/templates/static.template.css","static/static.css","text/plain"]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -19,9 +19,6 @@
"--screenshot",
"[[$:/plugins/tiddlywiki/innerwiki/examples]]",
"4"
],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -16,9 +16,6 @@
"--render","$:/core/templates/static.template.html","static.html","text/plain",
"--render","$:/core/templates/alltiddlers.template.html","alltiddlers.html","text/plain",
"--render","[!is[system]]","[encodeuricomponent[]addprefix[static/]addsuffix[.html]]","text/plain","$:/core/templates/static.tiddler.html",
"--render","$:/core/templates/static.template.css","static/static.css","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","katexdemo.html","text/plain"
]
"--render","$:/core/templates/static.template.css","static/static.css","text/plain"]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -13,9 +13,6 @@
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","markdowndemo.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","markdowndemo.html","text/plain"
]
"--rendertiddler","$:/core/save/all","markdowndemo.html","text/plain"]
}
}

View File

@@ -2,8 +2,11 @@ created: 20131127215321439
modified: 20140912135951542
title: $:/DefaultTiddlers
[[$:/plugins/tiddlywiki/internals]]
[[$:/AdvancedSearch]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples]]
[[TiddlyWiki Pre-release]]
HelloThere
[[Quick Start]]
[[Find Out More]]
[[TiddlyWiki on the Web]]
[[Testimonials and Reviews]]
GettingStarted
Community

View File

@@ -6,6 +6,12 @@ tags: [[$:/tags/test-spec]]
Tests <$action-deletefield />.
\*/
(function(){
/* jslint node: true, browser: true */
/* eslint-env node, browser, jasmine */
/* eslint no-mixed-spaces-and-tabs: ["error", "smart-tabs"]*/
/* global $tw, require */
"use strict";
describe("<$action-deletefield /> tests", function() {
@@ -166,3 +172,5 @@ it("should correctly delete fields", function() {
});
});
})();

View File

@@ -6,6 +6,7 @@ tags: [[$:/tags/test-spec]]
Tests the fakedom that Tiddlywiki occasionally uses.
\*/
(function(){
"use strict";
describe("fakedom tests", function() {
@@ -19,3 +20,5 @@ describe("fakedom tests", function() {
expect($tw.fakeDocument.createTextNode("text").TEXT_NODE).toBe(3);
});
});
})();

View File

@@ -6,6 +6,7 @@ tags: [[$:/tags/test-spec]]
Tests for integrity of the core plugins, languages, themes and editions
\*/
(function(){
"use strict";
if($tw.node) {
@@ -46,3 +47,6 @@ if($tw.node) {
});
});
}
})();

View File

@@ -3,7 +3,10 @@ title: test-widget-event.js
type: application/javascript
tags: [[$:/tags/test-spec]]
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
describe("Widget Event Listeners", function() {
@@ -217,3 +220,5 @@ describe("Widget Event Listeners", function() {
});
});
})();

View File

@@ -6,6 +6,7 @@ tags: [[$:/tags/test-spec]]
Tests the wikitext rendering pipeline end-to-end. We also need tests that individually test parsers, rendertreenodes etc., but this gets us started.
\*/
(function(){
"use strict";
describe("Widget module", function() {
@@ -88,3 +89,4 @@ describe("Widget module", function() {
});
})();

View File

@@ -2,8 +2,7 @@
"description": "TiddlyWiki core tests",
"plugins": [
"tiddlywiki/jasmine",
"tiddlywiki/geospatial",
"tiddlywiki/internals"
"tiddlywiki/geospatial"
],
"themes": [
"tiddlywiki/vanilla",

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -13,9 +13,6 @@
"build": {
"index": [
"--rendertiddler","$:/core/save/all","index.html","text/plain"
],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
]
}
}

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -10,9 +10,6 @@
],
"build": {
"index": [
"--render","$:/core/save/all","index.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
]
"--render","$:/core/save/all","index.html","text/plain"]
}
}

View File

@@ -1,11 +0,0 @@
created: 20250211092107689
modified: 20250211092307574
tags: Definitions
title: HTML Tags
type: text/vnd.tiddlywiki
<<<
In HTML, a tag is used for creating an element.
The name of an HTML element is the name that appears at the beginning of the element's start tag and at the end of the element's end tag (if the element has an end tag). For example, the p in the `<p>` start tag and `</p>` end tag is the name of the HTML paragraph element. Note that an element name in an end tag is preceded by a slash character: `</p>`, and that for void elements, the end tag is neither required nor allowed.
<<< https://developer.mozilla.org/en-US/docs/Glossary/Tag

View File

@@ -1,6 +1,6 @@
breadcrumbs: [[Filter Step]]
created: 20140410103123179
modified: 20250302200615061
modified: 20230410114132501
tags: Filters
title: Filter Operators
type: text/vnd.tiddlywiki
@@ -21,7 +21,7 @@ type: text/vnd.tiddlywiki
A <<.def "filter operator">> is a predefined keyword attached to an individual step of a [[filter|Filters]]. It defines the particular action of that step.
<<.tip """In general, each first [[filter step|Filter Step]] of a [[filter run|Filter Run]] not given any input titles receives the output of <$link to="all Operator">''[all[tiddlers]]''</$link> as its input.""" title:"Important">>
''Important:'' In general, each first [[filter step|Filter Step]] of a [[filter run|Filter Run]] not given any input titles receives the output of <$link to="all Operator">[all[tiddlers]]</$link> as its input.
''Table legend:''

View File

@@ -6,6 +6,22 @@ tags: Welcome
title: HelloThere
type: text/vnd.tiddlywiki
<$let json=`{"parseTree":{"input":[1,2,3]}}`>
<$log
message="HelloThere"
text1={{{[<json>jsonextract[parseTree]then[...]else[XXXX]]}}}
text2={{{[<json>jsonextract[parsetree]then[...]else[XXXX]]}}}
text3={{{[<json>jsonextract[parseTree]then[...]else[XXXX]]}}}
text4={{{[<json>jsonextract[parsetree]then[...]else[XXXX]]}}}
text5={{{[<json>jsonextract[parseTree]then[...]else[XXXX]]}}}
text6={{{[<json>jsonextract[parsetree]then[...]else[XXXX]]}}}
text7={{{[<json>jsonextract[parseTree]then[...]else[XXXX]]}}}
text8={{{[<json>jsonextract[parsetree]then[...]else[XXXX]]}}}
/>
</$let>
!!.tc-hero-heading ''Welcome to TiddlyWiki, a unique [[non-linear|Philosophy of Tiddlers]] notebook for [[capturing|Creating and editing tiddlers]], [[organising|Structuring TiddlyWiki]] and [[sharing|Sharing your tiddlers with others]] complex information''
Use it to keep your [[to-do list|TaskManagementExample]], to plan an [[essay or novel|"TiddlyWiki for Scholars" by Alberto Molina]], or to organise your wedding. Record every thought that crosses your brain, or build a flexible and responsive website.

View File

@@ -1,6 +1,6 @@
created: 20180111122953142
modified: 20181113084151268
tags: OfficialPlugins [[Plugin Editions]]
tags: OfficialPlugins
title: Dynaview Plugin
type: text/vnd.tiddlywiki

View File

@@ -1,17 +0,0 @@
created: 20250302053159467
modified: 20250302053316068
tags: OfficialPlugins [[Plugin Editions]]
title: Geospatial Plugin
type: text/vnd.tiddlywiki
The Geospatial Plugin adds new primitives to the TiddlyWiki platform to enable non-developers to build sophisticated interactive geospatial applications.
It incorporates a number of third party libraries and online services:
* [[Leaflet.js|https://leafletjs.com/]], an open source library to display interactive maps
* [[Turf.js|https://turfjs.org/]], an open source library to perform geospatial calculations with [[GeoJSON|https://en.wikipedia.org/wiki/GeoJSON]] objects
* [[TravelTime|https://traveltime.com/]], a commercial API for [[geocoding|https://traveltime.com/features/geocoding]], [[routing|https://traveltime.com/features/multi-modal-routing]] and [[isochrones|https://traveltime.com/features/isochrones]]
* [[Flickr|https://www.flickr.com/services/api/]], a free API for retrieving geotagged photographs
* [[OpenLocationCode|https://github.com/google/open-location-code]], Google's open source library for converting to and from Open Location Codes (also known as [[PlusCodes|https://maps.google.com/pluscodes/]])
Try it out at https://tiddlywiki.com/plugins/tiddlywiki/geospatial/

View File

@@ -1,6 +1,6 @@
created: 20190127104143725
modified: 20190127104143725
tags: OfficialPlugins [[Plugin Editions]]
tags: OfficialPlugins
title: Innerwiki Plugin
type: text/vnd.tiddlywiki

View File

@@ -1,6 +1,6 @@
created: 20201228143125000
modified: 20250302051857380
tags: OfficialPlugins [[Plugin Editions]]
modified: 20201228143125000
tags: OfficialPlugins
title: Share Plugin
type: text/vnd.tiddlywiki
@@ -10,5 +10,3 @@ This experimental plugin provides tools to share tiddlers via URLs, comprising:
* The ability to load a group of tiddlers from the browser location hash at startup
* Wizard and templates to create URLs from group of tiddlers
See the demo at [ext[https://tiddlywiki.com/share|share]]

View File

@@ -1,9 +0,0 @@
created: 20250302052635425
modified: 20250302052905312
tags: OfficialPlugins [[Plugin Editions]]
title: Tour Plugin
type: text/vnd.tiddlywiki
The tour plugin allows interactive learning tours to be created and presented in TiddlyWiki.
The demo TiddlyWiki interactive tour can be seen at https://tiddlywiki.com/tour

View File

@@ -48,6 +48,6 @@ $caption$
<<special-button>>
""">>
<<.warning """If macros are nested, textual substitution will only occur for the outermost macro. This is because by the time the inner macros are processed all the substitutions will have already occurred""">>
<<.warning """If macros are nested, textual substitution will only occur for the outermost macro. Thi is because by the time the inner macros are processed all the substitutions will have already occurred""">>
A more formal [[presentation|Macro Definition Syntax]] of this syntax is also available.

View File

@@ -14,8 +14,13 @@ Planned features include:
* Instantaneous synchronisation of changes between the server and all connected clients
* Workflow processing on the server, for example to automatically compress images, or to archive webpages
MWS does require basic knowledge of the command line and Node.js but is designed to be as simple as possible to setup and use. A few simple commands are all that is needed to complete the installation and start the server.
MWS does require basic knowledge of the command line and Node.js but is designed to be as simple as possible to setup and use. Once downloaded, just two commands are needed to complete the installation and start the server:
MWS is currently under development at ~GitHub but it is already functional and usable:
```
npm install
npm start
```
https://github.com/TiddlyWiki/MultiWikiServer/
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/TiddlyWiki5/pull/7915]] but it is already functional and usable. Visit the MWS website for more information:
! https://mws.tiddlywiki.com/

View File

@@ -3,8 +3,10 @@ modified: 20140912135951542
title: $:/DefaultTiddlers
type: text/vnd.tiddlywiki
[[$:/plugins/tiddlywiki/internals]]
[[$:/AdvancedSearch]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro]]
[[$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples]]
HelloThere
[[Quick Start]]
[[Find Out More]]
[[TiddlyWiki on the Web]]
[[Testimonials and Reviews]]
GettingStarted
Community

View File

@@ -1,6 +1,6 @@
caption: action-setfield
created: 20141025120850184
modified: 20250322010115457
modified: 20150806171403798
tags: Widgets ActionWidgets
title: ActionSetFieldWidget
type: text/vnd.tiddlywiki
@@ -66,10 +66,3 @@ src='<$button>
<$action-navigate $to="$:/ControlPanel"/>
Go to Control Panel "Appearance" tab
</$button>'/>
Here is an example of a button that will update the value of an existing field in a tiddler
<$macrocall $name='wikitext-example-without-html'
src='<$button>
<$action-setfield $tiddler="Test" existing_field_name="new field value"/>
Update Field existing_field_name in tiddler Test
</$button>'/>

View File

@@ -1,7 +1,7 @@
caption: reveal
created: 20131024141900000
jeremy: tiddlywiki
modified: 20250211091937860
modified: 20240721175716320
tags: Widgets
title: RevealWidget
type: text/vnd.tiddlywiki
@@ -28,7 +28,7 @@ The content of the `<$reveal>` widget is displayed according to the rules given
|stateTitle |A title containing the state, ''without'' TextReference. Gets preferred over the <<.attr state>> attribute |
|stateField |A ''field name'' which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|stateIndex |An ''index'' which is used to look for the state, if the attribute <<.attr stateTitle>> is present |
|tag |Overrides the default [[HTML Tags]] (`<div>` in block mode or `<span>` in inline mode) |
|tag |Overrides the default HTML element tag (`<div>` in block mode or `<span>` in inline mode) |
|type |The type of matching performed: ''match'', ''nomatch'', ''popup'', ''lt'', ''gt'', ''lteq'' or ''gteq'' |
|text |The text to match when the type is ''match'', ''nomatch'', ''lt'', ''gt'', ''lteq'' or ''gteq'' |
|class |An optional CSS class name to be assigned to the HTML element<br/>&raquo; Set to `tc-popup-keep` to make a popup "sticky", so it won't close when you click inside of it|

View File

@@ -1,4 +0,0 @@
title: $:/coreURL
tags: $:/tags/Global
\function coreURL() [[../../tiddlywikicore-$(version)$.js]substitute[]]

View File

@@ -12,9 +12,6 @@
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","index.html","text/plain"],
"external": [
"--render","$:/core/save/all-external-js","index.html","text/plain"
]
"--rendertiddler","$:/core/save/all","index.html","text/plain"]
}
}

View File

@@ -609,9 +609,3 @@ J. Ryan Stinnett, @jryans, 2025/01/04
Galen Huntington, @galenhuntington, 2025/01/19
@Rhys-T, 2025/01/23
@Rumman157, 2025/03/17
@bob.jansen@cultconv.com, 2025/03/22
Matthew Salmon, @matthewsalmon, 2025/04/24

View File

@@ -6,6 +6,7 @@ module-type: global
Confetti manager
\*/
(function(){
"use strict";
var confetti = require("$:/plugins/tiddlywiki/confetti/confetti.js");
@@ -48,3 +49,5 @@ ConfettiManager.prototype.reset = function () {
};
exports.ConfettiManager = ConfettiManager;
})();

View File

@@ -6,6 +6,7 @@ module-type: widget
Confetti widget
\*/
(function(){
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
@@ -59,3 +60,5 @@ ConfettiWidget.prototype.refresh = function(changedTiddlers) {
};
exports.confetti = ConfettiWidget;
})();

View File

@@ -6,6 +6,7 @@ module-type: startup
Setup the root widget event handlers
\*/
(function(){
"use strict";
// Export name and synchronous status
@@ -55,3 +56,5 @@ exports.startup = function() {
$tw.confettiManager.reset();
});
};
})();

View File

@@ -6,6 +6,7 @@ module-type: library
Manages the element spotlight effect
\*/
(function(){
"use strict";
function ElementSpotlight() {
@@ -128,3 +129,5 @@ ElementSpotlight.prototype.shineSpotlight = function(selectors) {
};
exports.ElementSpotlight = ElementSpotlight;
})();

View File

@@ -1,3 +1,5 @@
const { ElementSpotlight } = require("./element-spotlight");
/*\
title: $:/plugins/tiddlywiki/dynannotate/startup.js
type: application/javascript
@@ -6,6 +8,8 @@ module-type: startup
Startup the dyannotate background daemon to track the selection
\*/
(function(){
"use strict";
// Export name and synchronous status
@@ -52,3 +56,5 @@ exports.startup = function() {
$tw.dynannotate.elementSpotlight.shineSpotlight(selectors);
});
};
})();

View File

@@ -6,6 +6,9 @@ module-type: widget
Anchor widget to represent an innerwiki graphical anchor. Clone of the data widget
\*/
(function(){
"use strict";
exports.anchor = require("$:/core/modules/widgets/data.js").data;
})();

View File

@@ -1,13 +0,0 @@
title: $:/plugins/tiddlywiki/internals/docs
!! `<<inspect-filter>>` Procedure
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro}}
!!! `<<inspect-filter>>` Procedure Examples
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples}}
!! `inspect` Operator
{{$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator}}

View File

@@ -1,8 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab
tags: $:/tags/AdvancedSearch/FilterResults
caption: Inspect
list-after: $:/core/ui/AdvancedSearch/Filter/FilterResults/Results
Filter evaluation trace:
<$transclude $variable="inspect-filter" filter={{$:/temp/advancedsearch}} />

View File

@@ -1,44 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/ObserveResultsTab
tags: $:/tags/AdvancedSearch/FilterResults
caption: Observe
list-after: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab
Log traces of this filter expression in the background. A trace will be generated every time the filter is evaluated, regardless of the context. The trace is only saved if the results are different from previous traces.
<$checkbox tiddler="$:/config/FilterObservationionEnabled" field="text" checked="yes" unchecked="no" default="no">
Enable background filter observation
</$checkbox>
<$button>
<%if [all[shadows+tiddlers]tag[$:/tags/InspectableFilter]get[text]match{$:/temp/advancedsearch}count[]match[0]] %>
<$action-createtiddler $basetitle="$:/config/inspectable-filters/filter" tags="$:/tags/InspectableFilter" type="text/plain" text={{$:/temp/advancedsearch}}/>
<%endif%>
Enable logging for this filter
</$button>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/InspectableFilter]!has[draft.of]sort[]]" variable="inspectableFilter">
<div class="tc-box tc-inspectable-filter-box">
<div class="tc-box-header">
<$text text={{{ [<inspectableFilter>get[text]] }}}/> <$link to=<<inspectableFilter>>>{{$:/core/images/open-window}}</$link>
</div>
<div class="tc-box-content">
<ol>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/FilterInspectionOutput]!has[draft.of]!sort[modified]] :filter[<inspectableFilter>get[text]match{!!filter}]" variable="inspectionOutput">
<$let transclusion=<<inspectionOutput>>>
<li>
<div class="tc-box tc-inspectable-filter-trace-box">
<div class="tc-box-header">
<$text text={{{ [<inspectionOutput>get[modified]format:date[DDth mmm YYYY 0hh:0mm:0ss]] }}}/><$link to=<<inspectionOutput>>>{{$:/core/images/open-window}}</$link>
</div>
<div class="tc-box-content">
<$transclude $variable="inspect-filter-output-unframed" jsonOutput={{{ [<inspectionOutput>get[text]] }}} />
</div>
</div>
</li>
</$let>
</$list>
</ol>
</div>
</div>
</$list>

View File

@@ -1,17 +0,0 @@
caption: inspect-filter
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/InspectFilterMacro
type: text/vnd.tiddlywiki
The <<.def inspect-filter>> procedure displays a schematic representation of the filter evaluation process, including the input, output and intermediate results of evaluating the specified filter. It is based on the [[inspect operator|$:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator]].
By default the tabs are arranged horizontally above the content. To get vertical tabs, set the `orientation` parameter to `vertical`. This is useful for narrow windows or when the content is too wide to fit in a horizontal tab layout.
!! Parameters
;filter
: The filter to be inspected
;inputFilter
: Optionally, a filter defining the input titles for the filter to be inspected, defaulting to `[all[tiddlers]]`
;orientation
: Optionally, the orientation of the schematic representation, defaulting to `horizontal`. Set to `vertical` to display the tabs vertically

View File

@@ -1,27 +0,0 @@
caption: inspect
tags: [[Filter Operators]]
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/inspectoperator
type: text/vnd.tiddlywiki
The ''inspect'' operator evaluates a filter with the specified input titles and returns a JSON object containing the input, output and intermediate results of evaluating the specified filter.
|Operator Purpose |Inspect the evaluation of a filter to aid debugging |
|Operator Input |A selection of titles |
|Operator Output |A JSON object containing the input, output and intermediate results of evaluating the specified filter |
|Operator Parameter |The filter to be inspected |
The output JSON object contains the following properties:
* `input`: the input titles passed to the filter
* `inputFilter`: the filter being inspected
* `output`: the output titles resulting from evaluating the filter
* `evaluationTime`: the time taken to evaluate the filter, in milliseconds
* `runs`: an array of objects, each of which represents a single run of the filter. Each object contains the following properties:
** `prefixName`: the name of the prefix operator that was used in this run. Shortcut prefixes like `+` and `-` are expanded to their full names, e.g. `and` and `except`
** `input`: the input titles passed to the prefix operator
** `operations`: an array of objects, each of which represents the evaluation of a single operation that was performed in this run. Each object contains the following properties:
*** `operators`: an array of objects, each of which represents a single operator that was used in this run. Each object contains the following properties:
**** `operatorName`: the name of the operator
**** `operands`: an array of string operands passed to the operator
**** `input`: the input titles passed to the operator
**** `output`: the output titles resulting from evaluating the operator

View File

@@ -1,38 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/docs/inspectfiltermacro/examples
tags: [[Macro Examples]]
type: text/vnd.tiddlywiki
\procedure .example(n,eg,egvar)
<$let eg={{{ [<egvar>!is[blank]getvariable[]] :else[<eg>] }}}>
<div class="doc-example">
<$macrocall $name="copy-to-clipboard-above-right" src=<<eg>>/>
<$codeblock code=<<eg>>/>
<$list filter=`[title<.state-prefix>addsuffix{!!title}addsuffix[/]addsuffix[$(n)$]]` variable=".state">
<$reveal state=<<.state>> type="nomatch" text="show">
<dl>
<dd><$button set=<<.state>> setTo="show">Try it</$button></dd>
</dl>
</$reveal>
<$reveal state=<<.state>> type="match" text="show">
<dl>
<dd><$button set=<<.state>> setTo="">Hide</$button></dd>
</dl>
<blockquote class="doc-example-result">
<$transclude $variable="eg" $mode="block"/>
</blockquote>
</$reveal>
</$list>
</div>
</$let>
\end .example
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="1 2 3" inputFilter="[all[tiddlers]]"/>"""/>
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="1 2 3" inputFilter="[all[tiddlers]]" orientation="vertical"/>"""/>
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[title<currentTiddler>] [{$:/palette}length[]] [[marker]]" inputFilter="[all[tiddlers]]"/>"""/>
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[all[shadows+tiddlers]tag[$:/tags/MenuBar]!has[draft.of]] -[all[tiddlers+shadows]tag[$:/tags/TopLeftBarlimit[1]then[]else[$:/plugins/tiddlywiki/menubar/items/topleftbar]]" inputFilter="[all[tiddlers]]"/>
"""/>
<$macrocall $name=".example" eg="""<$transclude $variable="inspect-filter" filter="[tags[]prefix[$:/]] :sort[length[]add[1]] +[first[2]tagging[]]" inputFilter="[all[tiddlers]]"/>"""/>

View File

@@ -1,5 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectFilterProcedures/Filters/SlowFilter
tags: $:/tags/Filter
filter: [all[tiddlers+shadows]limit[500]] :filter[<currentTiddler>length[]reverse[]multiply[3.14]]
description: [Internals Plugin] A filter that takes a long time to process

View File

@@ -1,214 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/InspectFilterProcedures
tags: $:/tags/Global
\whitespace trim
\procedure inspect-list(jsonList)
<$let
transclusion={{{ [<jsonList>indexes[]count[]addprefix[-list-]] }}}
state=<<qualify "$:/temp/filter-inspector/list">>
stateMaxRows={{{ [<state>addsuffix[max-rows]] }}}
maxRows={{{ [<stateMaxRows>get[text]!match[]else[10]] }}}
stateScroll={{{ [<state>addsuffix[scroll]] }}}
>
<$text text=<<stateScroll>>/>
<$scrollable class="tc-box-content-list-scollable" bind=<<stateScroll>>>
<div class="tc-box-content-list">
<$list filter="[<jsonList>jsonindexes[]nsort[]limit<maxRows>]" variable="indexList">
<$list-template>
<div class="tc-box-content-list-item">
<$slot $name="list-item"/>
</div>
</$list-template>
<$list-empty>
<div class="tc-box-content-list-empty">
(No items)
</div>
</$list-empty>
</$list>
<%if [<jsonList>jsonindexes[]count[]compare:number:gt<maxRows>] %>
<div class="tc-box-content-list-more">
<$button class="tc-btn-invisible tc-box-content-full-width-button" style.fill="inherit">
<$action-setfield $tiddler=<<stateMaxRows>> text={{{ [<maxRows>add[10]] }}}/>
{{$:/core/images/chevron-down}}
<$text text="more"/>
</$button>
</div>
<%endif%>
</div>
</$scrollable>
\end inspect-list
\procedure inspect-foldable-text-list(jsonList,class:"tc-box")
<$let
transclusion={{{ [[link-list-]addsuffix<class>] }}}
>
<div class=<<class>>>
<$let
state=<<qualify "$:/temp/filter-inspector/list">>
stateFolded={{{ [<state>addsuffix[folded]] }}}
folded={{{ [<stateFolded>get[text]else[no]match[yes]] }}}
>
<div class="tc-box-header">
<$button class="tc-btn-invisible tc-box-content-full-width-button" style.fill="inherit">
<%if [<folded>match[yes]] %>
<$action-setfield $tiddler=<<stateFolded>> text="no"/>
<%else%>
<$action-setfield $tiddler=<<stateFolded>> text="yes"/>
<%endif%>
<$text text={{{ [<jsonList>jsonindexes[]count[]] }}}/>
{{$:/core/images/right-arrow}}
</$button>
</div>
<%if [<folded>!match[yes]] %>
<div class="tc-box-content">
<$transclude $variable="inspect-list" jsonList=<<jsonList>>>
<$fill $name="list-item">
<$text text={{{ [<jsonList>jsonget<indexList>] }}} />
</$fill>
</$transclude>
</div>
<%endif%>
</$let>
</div>
</$let>
\end inspect-foldable-text-list
\procedure inspect-operator(jsonOperator)
<div class="tc-box tc-inspect-operator-box">
<div class="tc-box-header">
<span class="">
<$text text={{{ [<jsonOperator>jsonget[prefix]] }}} />
<$text text={{{ [<jsonOperator>jsonget[operatorName]] }}} />
</span>
<%if [<jsonOperator>jsonindexes[suffixes]length[]compare:number:gt[0]] %>
<$list filter="[<jsonOperator>jsonindexes[suffixes]nsort[]]" variable="indexSuffix">
<span class="tc-pill">
:<$text text={{{ [<jsonOperator>jsonget[suffixes],<indexSuffix>] }}} />
</span>
</$list>
<%endif%>
<$list filter="[<jsonOperator>jsonindexes[operands]nsort[]]" variable="indexOperand">
<div class="tc-split-pill">
<div class="tc-split-pill-top">
<%if [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[variable]match[true]] %>
<$text text="<"/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text=">"/>
<%elseif [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[indirect]match[true]] %>
<$text text="{"/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text="}"/>
<%else%>
<$text text="["/><$text text={{{ [<jsonOperator>jsonget[parseTree],[operands],<indexOperand>,[text]] }}}/><$text text="]"/>
<%endif%>
</div>
<div class="tc-split-pill-bottom">
<$text text={{{ [<jsonOperator>jsonget[operands],<indexOperand>] }}} />
</div>
</div>
</$list>
</div>
<div class="tc-box-content">
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOperator>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
</div>
</div>
\end inspect-operator
\procedure inspect-operation(jsonOperation,indexOperation)
<div class="tc-box tc-inspect-operation-box">
<div class="tc-box-header">
<span class="">Evaluation</span>
<span class="tc-pill"><$text text=<<indexOperation>> /></span>
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOperation>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
</div>
<div class="tc-box-content">
<$list filter="[<jsonOperation>jsonindexes[operators]nsort[]]" variable="indexOperator">
<$let
transclusion={{{ [[operator-]addsuffix<indexOperator>] }}}
jsonOperator={{{ [<jsonOperation>jsonextract[operators],<indexOperator>] }}}
>
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOperator>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
<$transclude $variable="inspect-operator" jsonOperator=<<jsonOperator>>/>
</$let>
</$list>
<$list filter="[<jsonOperation>jsonindexes[operators]nsort[]last[1]]" variable="indexOperator">
<$let
transclusion={{{ [[operator-]addsuffix<indexOperator>] }}}
jsonOperator={{{ [<jsonOperation>jsonextract[operators],<indexOperator>] }}}
>
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOperator>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
</$let>
</$list>
</div>
</div>
\end inspect-operation
\procedure inspect-run(jsonRun)
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonRun>jsonextract[input]] }}} class="tc-box tc-inspect-input-box"/>
<div class="tc-box tc-inspect-run-box">
<div class="tc-box-header">
<span class="">
<%if [<jsonRun>jsonget[prefix]!match[]] %>
<$text text={{{ [<jsonRun>jsonget[prefix]] }}} />
<$text text=" shortcut for "/>
<$text text={{{ [<jsonRun>jsonget[prefixName]addprefix[:]] }}} />
<%else%>
<$text text={{{ [<jsonRun>jsonget[prefixName]addprefix[:]] }}} />
<%endif%>
</span>
<%if [<jsonRun>jsonindexes[suffixes]length[]compare:number:gt[0]] %>
<$list filter="[<jsonRun>jsonindexes[suffixes]nsort[]]" variable="indexSuffix">
<span class="tc-pill">
:<$text text={{{ [<jsonRun>jsonget[suffixes],<indexSuffix>] }}} />
</span>
</$list>
<%endif%>
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonRun>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
</div>
<div class="tc-box-content">
<div class="tc-inspect-operations-wrapper">
<$list filter="[<jsonRun>jsonindexes[operations]nsort[]]" variable="indexOperation">
<$let transclusion={{{ [[operation-]addsuffix<indexOperation>] }}}>
<$transclude $variable="inspect-operation" jsonOperation={{{ [<jsonRun>jsonextract[operations],<indexOperation>] }}} indexOperation=<<indexOperation>>/>
</$let>
</$list>
</div>
</div>
</div>
\end inspect-run
\procedure inspect-filter-output-unframed(jsonOutput,orientation:"horizontal")
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
<div class={{{ tc-inspect-filter-box tc-inspect-filter-box-unframed [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
<$list filter="[<jsonOutput>jsonindexes[runs]nsort[]]" variable="indexRun">
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
<$transclude $variable="inspect-run" jsonRun={{{ [<jsonOutput>jsonextract[runs],<indexRun>] }}}/>
</$let>
</$list>
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOutput>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
</div>
</$scrollable>
\end inspect-filter-output-unframed
\procedure inspect-filter-output(jsonOutput,orientation:"horizontal")
<$scrollable bind={{{ [<qualify "$:/temp/filter-inspector/">addsuffix<filter>] }}}>
<div class={{{ tc-inspect-filter-box [<orientation>match[horizontal]then[tc-inspect-filter-box-horizontal]] +[join[ ]] }}}>
<div class="tc-box">
<div class="tc-box-header">
Filter
<span class="tc-pill"><$text text={{{ [<jsonOutput>jsonget[inputFilter]] }}}/></span>
Evaluation time <span class="tc-pill"><$text text={{{ [<jsonOutput>jsonget[evaluationTime]fixed[8]] }}}/></span> milliseconds
</div>
<div class="tc-box-content">
<$list filter="[<jsonOutput>jsonindexes[runs]nsort[]]" variable="indexRun">
<$let transclusion={{{ [[run-]addsuffix<indexRun>] }}}>
<$transclude $variable="inspect-run" jsonRun={{{ [<jsonOutput>jsonextract[runs],<indexRun>] }}}/>
</$let>
</$list>
<$transclude $variable="inspect-foldable-text-list" jsonList={{{ [<jsonOutput>jsonextract[output]] }}} class="tc-box tc-inspect-output-box"/>
</div>
</div>
</div>
</$scrollable>
\end inspect-filter-output
\procedure inspect-filter(filter,inputFilter:"[all[tiddlers]]",orientation:"horizontal")
<$transclude $variable="inspect-filter-output" jsonOutput={{{ [subfilter<inputFilter>inspect<filter>] }}} orientation=<<orientation>> />
\end inspect-filter

View File

@@ -1,29 +0,0 @@
/*\
title: $:/plugins/tiddlywiki/internals/filterinspection/modules/inspect.js
type: application/javascript
module-type: filteroperator
Filter operator for inspecting the evaluation of a filter
\*/
"use strict";
var getWrappers = $tw.plugins.internals.getWrappers;
/*
Export our filter function
*/
exports.inspect = function(source,operator,options) {
var inputFilter = operator.operands[0] || "",
results,
wrappers = getWrappers(function(output) {
results = output;
},inputFilter);
// Compile the filter with wrapper functions to log the details
var compiledFilter = options.wiki.compileFilter(inputFilter,{
wrappers: wrappers
});
compiledFilter.call(options.wiki,source,options.widget);
return [JSON.stringify(results)];
};

View File

@@ -1,212 +0,0 @@
/*\
title: $:/plugins/tiddlywiki/internals/filterinspection/modules/startup.js
type: application/javascript
module-type: startup
Install hooks
\*/
"use strict";
// Export name and synchronous status
exports.name = "internals-plugin";
exports.before = ["startup"];
exports.synchronous = true;
exports.startup = function() {
// Publish public methods
$tw.plugins = $tw.plugins || {};
$tw.plugins.internals = {
getWrappers: getWrappers
};
// We accumulate the output of the filter inspection into an array. We can't directly write to the wiki since we might be in
// the middle of the refresh cycle, when writes to the wiki are not allowed
var accumulator = [];
// Add our hook for each filter evaluation
$tw.hooks.addHook("th-filter-evaluation",function(filterString,wrappers) {
// Check that filter observation is enabled
if($tw.wiki.getTiddlerText("$:/config/FilterObservationionEnabled","no") !== "yes") {
return wrappers;
}
// Get the list of filters to be inspected
var inspectedFilters = $tw.wiki.getTiddlersWithTag("$:/tags/InspectableFilter");
// Check whether this is a filter we want to inspect
if(inspectedFilters.indexOf(filterString) === -1) {
return wrappers;
}
// Don't do anything if there are already wrappers
if(wrappers.prefix || wrappers.operation || wrappers.operator) {
return wrappers;
}
// Flush the accumulator, making each filter inspection output record into a separate tiddler
var flushAccumulator = function() {
if(accumulator.length) {
$tw.utils.each(accumulator,function(jsonInspectionOutput) {
// Get the output as a string
var stringInspectionOutput = JSON.stringify(jsonInspectionOutput);
// Compute the log prefix and its length
var logPrefix = `$:/temp/filter-inspection/${ + $tw.utils.stringifyDate(new Date())}: `,
logPrefixLength = logPrefix.length;
// Check if the the output is the same as the last log with the same filter
var logTitles = [];
$tw.wiki.each(function(tiddler,title) {
if(title.substring(logPrefixLength) === jsonInspectionOutput.inputFilter) {
logTitles.push(title);
}
});
var alreadyLogged = false;
$tw.utils.each(logTitles,function(title) {
var jsonLog = $tw.wiki.getTiddlerData(title);
if($tw.utils.isArrayEqual(jsonLog.output,jsonInspectionOutput.output)) {
alreadyLogged = true;
}
});
if(alreadyLogged) {
return;
}
// Add the log tiddler
var tiddlerFields = {
title: `${logPrefix}${jsonInspectionOutput.inputFilter}`,
tags: ["$:/tags/FilterInspectionOutput"],
text: stringInspectionOutput,
filter: jsonInspectionOutput.inputFilter,
type: "application/json"
}
// console.log("Adding " + JSON.stringify(tiddlerFields));
$tw.wiki.addTiddler(new $tw.Tiddler($tw.wiki.getCreationFields(),$tw.wiki.getModificationFields(),tiddlerFields));
});
accumulator = [];
}
};
// Get our wrappers
return getWrappers(function(output) {
// Schedule a flush
if(accumulator.length === 0) {
$tw.utils.nextTick(function() {
flushAccumulator();
});
}
accumulator.push(output);
},filterString);
});
};
/*
Return the wrappers for evaluating a given filter
fnDone is a function that will be called with the output of the filter evaluation as the single argument
inputFilter is the filter to be evaluated
*/
function getWrappers(fnDone,inputFilter) {
// Skeleton output record
var output = {
inputFilter: inputFilter,
input: [],
runs: []
};
// Keep track of where the current run and the current operation are being written
var currentRun,currentOperation;
// The starting evaluation time stamp
var filterStartTime;
// Compile the filter with wrapper functions to log the details
return {
start: function(source) {
// Save the input so that we have it in the output record
source(function(tiddler,title) {
output.input.push(title);
});
// Start the timer
filterStartTime = $tw.utils.timer();
},
prefix: function(filterRunPrefixFunction,operationFunction,innerOptions) {
// Function to be called at the start of each filter run
return function(results,innerSource,innerWidget) {
// Save the details of this filte run
var details ={
input: results.toArray(),
prefixName: innerOptions.prefixName,
prefix: innerOptions.prefix,
suffixes: innerOptions.suffixes,
operations: []
};
// Save the current run so that we can add operations to it
currentRun = details.operations;
// Save the start time
var startTime = $tw.utils.timer();
// Get the filter run prefix function
var innerResults = filterRunPrefixFunction.call(null,operationFunction,innerOptions);
// Invoke the filter run
innerResults(results,innerSource,innerWidget);
// Save the end time
details.evaluationTime = $tw.utils.timer(startTime);
// Save the results of the filter run
details.output = results.toArray();
output.runs.push(details);
};
},
operation: function(operationFunction,operation) {
// Record the operation
var details = {
operators: []
}
// Save the start time
var startTime = $tw.utils.timer();
// Keep track of where the current operation should be being written
currentOperation = details.operators;
// Invoke the operation
operationFunction();
// Save the end time
details.evaluationTime = $tw.utils.timer(startTime);
// Save the results of the operation
currentRun.push(details);
},
operator: function(operatorFunction,innerSource,innerOperator,innerOptions) {
// Record the operator
var details = {
operatorName: innerOperator.operatorName,
operands: innerOperator.operands,
parseTree: innerOperator.parseTree,
prefix: innerOperator.prefix,
suffix: innerOperator.suffix,
suffixes: innerOperator.suffixes,
regexp: innerOperator.regexp,
input: []
};
// Copy the input
innerSource(function(tiddler,title) {
details.input.push(title);
});
// Save this operation
currentOperation.push(details);
// Save the start time
var startTime = $tw.utils.timer();
// Invoke the operator
var innerResults = operatorFunction.apply(null,Array.prototype.slice.call(arguments,1));
// Save the end time
details.evaluationTime = $tw.utils.timer(startTime);
// Make sure the results are an array so that we can store them
if(!$tw.utils.isArray(innerResults)) {
var resultArray = [];
innerResults(function(tiddler,title) {
resultArray.push(title);
});
innerResults = resultArray;
}
// Store the results in the output
details.output = innerResults;
// Return the results
return innerResults;
},
done: function(results) {
// Store evaluation time
output.evaluationTime = $tw.utils.timer(filterStartTime);
// Save the results of the filter evaluation
output.output = results;
// console.log(`Inspected ${JSON.stringify(output,null,4)}`);
// Invoke the done function
if(fnDone) {
fnDone(output);
}
}
};
}

View File

@@ -1,188 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/styles
tags: $:/tags/Stylesheet
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
/*
** Headed box and pills
*/
.tc-box {
border: 1px solid var(--box-foreground-color););
border-radius: 4px;
margin: 0 0 0.5em 0;
}
.tc-box .tc-box {
margin: 0.5em;
}
.tc-box-header {
padding: 0.25em;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
color: var(--box-background-color);
fill: var(--box-background-color);
background-color: var(--box-foreground-color);
display: flex;
align-items: center;
}
.tc-box-header svg {
width: 1em;
height: 1em;
margin-left: 0.25em;
}
.tc-box-header button {
color: var(--box-background-color);
background-color: var(--box-foreground-color);
}
.tc-box-content {
min-width: 4em;
padding: 0.25em;
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
color: var(--box-foreground-color);
fill: var(--box-foreground-color);
background-color: var(--box-background-color);
}
.tc-box-content-list-scollable {
margin: -0.25em;
max-height: 25vh;
width: 12em;
}
.tc-box-content-list {
}
.tc-box-content-list-item {
font-size: 0.7em;
line-height: 1.1;
padding: 0.25em;
}
.tc-box-content-list-more {
font-size: 0.7em;
line-height: 1.1;
padding: 0.25em;
}
.tc-box-content-full-width-button {
display: block;
width: 100%;
text-align: left;
}
.tc-box-content-list-more,
.tc-box-content-list-more .tc-btn-invisible {
color: var(--box-background-color);
fill: var(--box-background-color);
background-color: var(--box-foreground-color);
}
.tc-box-content-list-item:nth-child(even) {
background: rgb(255, 255, 255, 0.5);
}
.tc-box-content-list-empty {
}
.tc-pill {
padding: 0.125em 0.25em;
margin: 0 0.25em;
border-radius: 6px;
color: var(--box-foreground-color);
background-color: var(--box-background-color);
}
.tc-split-pill {
display: inline-block;
padding: 0.125em 0.25em;
margin: 0 0.25em;
border-radius: 6px;
color: var(--box-foreground-color);
background-color: var(--box-background-color);
}
.tc-split-pill-top {
border-bottom: 1px solid var(--box-foreground-color);
}
.tc-split-pill-bottom {
}
/*
** Filter Inspection
*/
.tc-inspect-filter-box {
--box-background-color: <<colour code-border>>;
--box-foreground-color: <<colour code-foreground>>;
}
.tc-inspectable-filter-box {
--box-background-color: #ffebe1;
--box-foreground-color: #ff3f00;
}
.tc-inspectable-filter-trace-box {
--box-background-color: #ffdec1;
--box-foreground-color: #ff7a00;
}
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal {
display: flex;
}
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal > .tc-box > .tc-box-content,
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal.tc-inspect-filter-box-unframed,
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-run-box > .tc-box-content,
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-operation-box > .tc-box-content,
.tc-inspect-filter-box.tc-inspect-filter-box-horizontal .tc-inspect-operator-box > .tc-box-content {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
}
.tc-inspectable-filter-box > .tc-box-content > ol {
list-style: none;
padding-left: 0;
}
.tc-inspect-operations-wrapper {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.tc-inspect-run-box {
--box-background-color: #ffffcc;
--box-foreground-color: #444400;
}
.tc-inspect-operation-box {
--box-background-color: #ccffcc;
--box-foreground-color: #004400;
}
.tc-inspect-operator-box {
--box-background-color: #ffcccc;
--box-foreground-color: #440000;
}
.tc-box.tc-inspect-input-box {
--box-background-color: #ffccff;
--box-foreground-color: #440044;
}
.tc-box.tc-inspect-output-box {
--box-background-color: #4fd3d3;
--box-foreground-color: #004444;
}

View File

@@ -1,28 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/tests/wikitext/Simple
description: Test filter inspection
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
\procedure test-filter()
1 2 3 :sort[length[]add[1]]
\end
\function test-filter-wrapper()
[inspect<test-filter>]
\end
<$text text=<<test-filter>>/>
-
<$text text={{{ [<test-filter-wrapper>jsonindexes[]join[,]] }}}/>
-
<$text text={{{ [<test-filter-wrapper>jsonindexes[inputFilter]join[,]] }}}/>
-
<$text text={{{ [<test-filter-wrapper>jsonindexes[runs]join[,]] }}}/>
+
title: ExpectedResult
<p>1 2 3 :sort[length[]add[1]]-evaluationTime,input,inputFilter,output,runs--0,1,2,3</p>

View File

@@ -1,3 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/viewtemplatebody
<$transclude $variable="inspect-filter-output" jsonOutput={{!!text}} />

View File

@@ -1,5 +0,0 @@
title: $:/plugins/tiddlywiki/internals/filterinspection/cascades/viewtemplatebody
tags: $:/tags/ViewTemplateBodyFilter
list-before:
[tag[$:/tags/FilterInspectionOutput]type[application/json]then[$:/plugins/tiddlywiki/internals/filterinspection/viewtemplatebody]]

View File

@@ -1,2 +0,0 @@
title: $:/state/tab--1498284803
text: $:/core/ui/AdvancedSearch/Filter

View File

@@ -1,2 +0,0 @@
title: $:/state/tab--251342953
text: $:/plugins/tiddlywiki/internals/filterinspection/InspectResultsTab

View File

@@ -1,2 +0,0 @@
title: $:/config/FilterObservationionEnabled
text: yes

View File

@@ -1,5 +0,0 @@
title: $:/plugins/tiddlywiki/internals/testfilter
tags: $:/tags/InspectableFilter
type: text/plain
[list[$:/StoryList]]

View File

@@ -2,6 +2,6 @@
"title": "$:/plugins/tiddlywiki/internals",
"name": "Internals",
"description": "Tools for exploring the internals of TiddlyWiki",
"list": "readme docs",
"list": "readme",
"stability": "STABILITY_2_STABLE"
}

View File

@@ -1,24 +1,10 @@
title: $:/plugins/tiddlywiki/internals/readme
This plugin adds several features to help explore the internals of TiddlyWiki, and to debug wikitext and filters.
This plugin adds features to help explore the internals of TiddlyWiki:
!! Inspecting Filter Traces
* New preview panes showing:
** the parse tree
** the widget tree
** the raw HTML output
Filter inspection is based on a schematic visualisation that traces all the steps involved in evaluating a filter. These traces can be generated and accessed in several ways:
* Via two new tabs under the Advanced Search filter results:
** The ''Inspect'' tab shows the schematic trace for the current filter
** The ''Observe'' tab allows the current filter to be logged in the background. A new trace is generated every time the filter is evaluated, regardless of the context, if the results are different from previous evaluations
* Directly using the `<<inspect-filter>>` procedure, or the underlying `inspect[]` operator
Note that observing a filter is not the same as logging it. Observing a filter means that the filter is evaluated in the background, and a new trace is generated every time the filter is evaluated, regardless of the context. Logging a filter means that the filter is evaluated in the background, but only if the results are different from previous evaluations.
Filter observation has a performance impact, and disables certain optimisations such as caching of compiled filters.
!! Inspecting Parse Trees and Widget Trees
New preview panes for the tiddler editor that show
* the parse tree
* the widget tree
* the raw HTML output
The first two include a dropdown for choosing block vs. inline parsing mode.

View File

@@ -0,0 +1,4 @@
title: $:/plugins/tiddlywiki/internals/styles
tags: $:/tags/Stylesheet
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock

View File

@@ -6,6 +6,7 @@ module-type: widget
barcodereader widget for reading barcodes
\*/
(function(){
"use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget;
@@ -82,3 +83,5 @@ BarCodeReaderWidget.prototype.refresh = function(changedTiddlers) {
};
exports.barcodereader = BarCodeReaderWidget;
})();

View File

@@ -66,7 +66,7 @@ Generate sharing link
!! 5 - Export the shared tiddlers
<$button>
<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/exporters/JsonFile" exportFilter={{$:/config/plugins/share/filter}} filename="tiddlers.json" type="application/json"/>
<$action-sendmessage $message="tm-download-file" $param="$:/core/templates/exporters/JsonFile" exportFilter={{$:/config/plugins/share/filter}} filename="tiddlers.json"/>
Export as JSON
</$button>