1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-14 05:59:48 +00:00

Compare commits

..

27 Commits

Author SHA1 Message Date
jeremy@jermolene.com
243e2980f0 Fix docs date 2022-09-24 14:07:14 +01:00
jeremy@jermolene.com
fb5786dcf0 Fix version number 2022-09-24 14:06:09 +01:00
jeremy@jermolene.com
227a5a0cd0 Initial Commit 2022-09-24 14:02:02 +01:00
jeremy@jermolene.com
dd66fcc759 Merge branch 'tiddlywiki-com' 2022-09-24 11:06:39 +01:00
jeremy@jermolene.com
8ebb9ef442 Typo from a981f8ccfe
Fixes #6955
2022-09-24 10:55:22 +01:00
jeremy@jermolene.com
81ac987484 Optimise variable prototype chain handling
With this improvement and 53d229592d I'm measuring a 10-15% performance improvement between v5.2.3 and master using https://github.com/Jermolene/tiddlywiki-performance-test-rig
2022-09-24 08:28:16 +01:00
jeremy@jermolene.com
0a00da6db9 Optimise fake dom
Object.setPrototypeOf() appears to be significantly faster
2022-09-23 18:09:45 +01:00
jeremy@jermolene.com
53d229592d Optimise wiki.getTiddler() 2022-09-23 18:09:16 +01:00
jeremy@jermolene.com
166a156584 Fix typo: Safe mode should prevent globally disabling parser rules 2022-09-23 18:08:28 +01:00
jeremy@jermolene.com
c5d3d4c26e Disable wiki indexers in safe mode 2022-09-23 18:07:46 +01:00
Robin Munn
51bdf60ee8 Fix bug when using built-in list field as listField parameter to checkbox widget (#6897)
* Fix bug with checkbox widget and `list` field

The `list` field is stored as a list and frozen against modifications,
and getFieldList() returns it directly without creating a copy. So
before we modify it, we need to make a copy so we're not modifying a
frozen list. This bug doesn't manifest with custom fields, which are
stored as strings, only with the built-in `list` field.

* Fix checkboxes referencing non-existent tiddlers

This fixes the "tiddler is undefined" error when a checkbox's listField
property references a tiddler that doesn't (yet) exist.

* Better logic for checkbox listField handling

If the field contains an array, then it's almost certainly referenced
elsewhere and needs a defensive copy made. If it contained a string,
then it's safe to modify without making a defensive copy.
2022-09-22 18:52:55 +01:00
jeremy@jermolene.com
50f54ba6ca Merge branch 'tiddlywiki-com' 2022-09-22 10:34:41 +01:00
jeremy@jermolene.com
1a0ab68dec Complete fix for a981f8ccfe 2022-09-22 10:34:27 +01:00
jeremy@jermolene.com
bb67f96562 Merge branch 'tiddlywiki-com' 2022-09-21 09:32:33 +01:00
jeremy@jermolene.com
a981f8ccfe Partial fix for wikitext example macros
They don't work when the src text contains variable substitution syntax.
2022-09-21 09:32:18 +01:00
白宦成
859d15a446 Signing the CLA (#6951) 2022-09-17 16:52:05 +01:00
Cameron Fischer
debfd42d51 Log message not to have spaces and <empty string> (#6947) 2022-09-15 12:10:33 +01:00
twMat
fe365354d0 [doc] Update WidgetMessage: tm-new-tiddler (#6945)
...
2022-09-13 17:20:28 +01:00
jeremy@jermolene.com
d825f1c875 Use view template body cascade for the default preview 2022-09-10 11:01:29 +01:00
jeremy@jermolene.com
fe74a776e9 Docs: Add note for retrieving system tiddlers via HTTP under Node.js
See #6866
2022-09-09 10:02:26 +01:00
Roma Hicks
93e1a632b8 Updated URL to new public site. (#6496) 2022-09-05 18:04:47 +01:00
jeremy@jermolene.com
9b7edfc1a7 Revert changes to parse tree preview
This implementation requires #6666
2022-09-03 10:55:15 +01:00
jeremy@jermolene.com
3b2c64a85b Update release note 2022-09-02 21:28:32 +01:00
Jeremy Ruston
35b9faaa89 JSON Filter Operators (Revised Attempt) (#6936)
* First commit

Cherry-picked from #6666

* Adjust release version number

Just in case we decide to make a release before we merge #6666
2022-09-02 18:15:45 +01:00
tw-FRed
11b258a14b Fix tag pills style (#6934) 2022-09-01 08:38:26 +01:00
Jeremy Ruston
c8ad385947 Docs: Update code of conduct 2022-08-19 11:15:57 +00:00
Marxsal
c1f6e02d14 Fix missing links in Getting Started. (#6900)
* Fix empty links in Getting Started.

* Remove standalone TH reference and combine lines.
2022-08-19 08:14:04 +01:00
31 changed files with 601 additions and 205 deletions

View File

@@ -1230,13 +1230,16 @@ $tw.Wiki = function(options) {
this.getTiddler = function(title) {
if(title) {
var t = tiddlers[title];
if(t instanceof $tw.Tiddler) {
if(t !== undefined) {
return t;
} else if(title !== undefined && shadowTiddlers[title]) {
return shadowTiddlers[title].tiddler;
} else {
var s = shadowTiddlers[title];
if(s !== undefined) {
return s.tiddler;
}
}
return undefined;
}
return undefined;
};
// Get an array of all tiddler titles
@@ -2416,7 +2419,7 @@ $tw.boot.initStartup = function(options) {
$tw.utils.registerFileType("application/epub+zip","base64",".epub");
$tw.utils.registerFileType("application/octet-stream","base64",".octet-stream");
// Create the wiki store for the app
$tw.wiki = new $tw.Wiki();
$tw.wiki = new $tw.Wiki($tw.safeMode && {enableIndexers: []});
// Install built in tiddler fields modules
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
// Install the tiddler deserializer modules

View File

@@ -116,7 +116,7 @@ WikiParser.prototype.loadRemoteTiddler = function(url) {
*/
WikiParser.prototype.setupRules = function(proto,configPrefix) {
var self = this;
if(!$tw.safemode) {
if(!$tw.safeMode) {
$tw.utils.each(proto,function(object,name) {
if(self.wiki.getTiddlerText(configPrefix + name,"enable") !== "enable") {
delete proto[name];

View File

@@ -42,7 +42,7 @@ var TW_TextNode = function(text) {
this.textContent = text + "";
};
TW_TextNode.prototype = Object.create(TW_Node.prototype);
Object.setPrototypeOf(TW_TextNode,TW_Node.prototype);
Object.defineProperty(TW_TextNode.prototype, "nodeType", {
get: function() {
@@ -67,7 +67,7 @@ var TW_Element = function(tag,namespace) {
this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml";
};
TW_Element.prototype = Object.create(TW_Node.prototype);
Object.setPrototypeOf(TW_Element,TW_Node.prototype);
Object.defineProperty(TW_Element.prototype, "style", {
get: function() {

View File

@@ -48,7 +48,9 @@ Logger.prototype.log = function(/* args */) {
this.saveBufferLogger.buffer = this.saveBufferLogger.buffer.slice(-this.saveBufferLogger.saveLimit);
}
if(console !== undefined && console.log !== undefined) {
return Function.apply.call(console.log, console, [$tw.utils.terminalColour(this.colour),this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0)).concat($tw.utils.terminalColour()));
var logMessage = [$tw.utils.terminalColour(this.colour) + this.componentName + ":"].concat(Array.prototype.slice.call(arguments,0));
logMessage[logMessage.length-1] += $tw.utils.terminalColour();
return Function.apply.call(console.log, console, logMessage);
}
}
};

View File

@@ -12,12 +12,26 @@ Parse tree utility functions.
/*global $tw: false */
"use strict";
/*
Add attribute to parse tree node
Can be invoked as (node,name,value) or (node,attr)
*/
exports.addAttributeToParseTreeNode = function(node,name,value) {
var attribute = {name: name, type: "string", value: value};
var attribute = typeof name === "object" ? name : {name: name, type: "string", value: value};
name = attribute.name;
node.attributes = node.attributes || {};
node.orderedAttributes = node.orderedAttributes || [];
node.attributes[name] = attribute;
if(node.orderedAttributes) {
var foundIndex = -1;
$tw.utils.each(node.orderedAttributes,function(attr,index) {
if(attr.name === name) {
foundIndex = index;
}
});
if(foundIndex === -1) {
node.orderedAttributes.push(attribute);
} else {
node.orderedAttributes[foundIndex] = attribute;
}
};

View File

@@ -66,14 +66,14 @@ CheckboxWidget.prototype.render = function(parent,nextSibling) {
CheckboxWidget.prototype.getValue = function() {
var tiddler = this.wiki.getTiddler(this.checkboxTitle);
if(tiddler || this.checkboxFilter) {
if(this.checkboxTag) {
if(tiddler && this.checkboxTag) {
if(this.checkboxInvertTag === "yes") {
return !tiddler.hasTag(this.checkboxTag);
} else {
return tiddler.hasTag(this.checkboxTag);
}
}
if(this.checkboxField || this.checkboxIndex) {
if(tiddler && (this.checkboxField || this.checkboxIndex)) {
// Same logic applies to fields and indexes
var value;
if(this.checkboxField) {
@@ -206,11 +206,18 @@ CheckboxWidget.prototype.handleChangeEvent = function(event) {
}
// Set the list field (or index) if specified
if(this.checkboxListField || this.checkboxListIndex) {
var listContents, oldPos, newPos;
var fieldContents, listContents, oldPos, newPos;
if(this.checkboxListField) {
listContents = tiddler.getFieldList(this.checkboxListField);
fieldContents = tiddler ? tiddler.fields[this.checkboxListField] : undefined;
} else {
listContents = $tw.utils.parseStringArray(this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex) || "") || [];
fieldContents = this.wiki.extractTiddlerDataItem(this.checkboxTitle,this.checkboxListIndex);
}
if($tw.utils.isArray(fieldContents)) {
// Make a copy so we can modify it without changing original that's refrenced elsewhere
listContents = fieldContents.slice(0);
} else {
listContents = $tw.utils.parseStringArray(fieldContents) || [];
// No need to copy since parseStringArray returns a fresh array, not refrenced elsewhere
}
oldPos = notValue ? listContents.indexOf(notValue) : -1;
newPos = value ? listContents.indexOf(value) : -1;

View File

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

View File

@@ -39,7 +39,10 @@ Compute the internal state of the widget
ImportVariablesWidget.prototype.execute = function(tiddlerList) {
var widgetPointer = this;
// Got to flush all the accumulated variables
this.variables = new this.variablesConstructor();
this.variables = Object.create(null);
if(this.parentWidget) {
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
}
// Get our parameters
this.filter = this.getAttribute("filter");
// Compute the filter

View File

@@ -38,9 +38,10 @@ Widget.prototype.initialise = function(parseTreeNode,options) {
this.parseTreeNode = parseTreeNode;
this.wiki = options.wiki;
this.parentWidget = options.parentWidget;
this.variablesConstructor = function() {};
this.variablesConstructor.prototype = this.parentWidget ? this.parentWidget.variables : {};
this.variables = new this.variablesConstructor();
this.variables = Object.create(null);
if(this.parentWidget) {
Object.setPrototypeOf(this.variables,this.parentWidget.variables);
}
this.document = options.document;
this.attributes = {};
this.children = [];

View File

@@ -5,6 +5,6 @@ caption: {{$:/language/EditTemplate/Body/Preview/Type/Output}}
\import [all[shadows+tiddlers]tag[$:/tags/Macro/View]!has[draft.of]] [all[shadows+tiddlers]tag[$:/tags/Macro/View/Body]!has[draft.of]]
<$set name="tv-tiddler-preview" value="yes">
<$transclude />
<$transclude tiddler={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/ViewTemplateBodyFilter]!is[draft]get[text]] :and[!is[blank]else[$:/core/ui/ViewTemplate/body/default]] }}} />
</$set>

View File

@@ -1,33 +0,0 @@
created: 20160504080001125
modified: 20160504080318928
title: $:/core/ui/TagTemplate
type: text/vnd.tiddlywiki
\define tag-styles()
background-color:$(backgroundColor)$;
fill:$(foregroundColor)$;
color:$(foregroundColor)$;
\end
\define tag-body-inner(colour,fallbackTarget,colourA,colourB)
<$set name="foregroundColor" value=<<contrastcolour target:"""$colour$""" fallbackTarget:"""$fallbackTarget$""" colourA:"""$colourA$""" colourB:"""$colourB$""">>>
<$set name="backgroundColor" value="""$colour$""">
<$button popup=<<qualify "$:/state/popup/tag">> class="tc-btn-invisible tc-tag-label" style=<<tag-styles>>>
<$transclude tiddler={{!!icon}}/> <$view field="fr-title"><$view field="title" format="text" /></$view>
</$button>
<$reveal state=<<qualify "$:/state/popup/tag">> type="popup" position="below" animate="yes"><div class="tc-drop-down"><$transclude tiddler="$:/core/ui/ListItemTemplate"/>
<hr>
<$list filter="[all[current]tagging[]]" template="$:/core/ui/ListItemTemplate"/>
</div>
</$reveal>
</$set>
</$set>
\end
\define tag-body(colour,palette)
<span class="tc-tag-list-item">
<$macrocall $name="tag-body-inner" colour="""$colour$""" fallbackTarget={{$palette$##tag-background}} colourA={{$palette$##foreground}} colourB={{$palette$##background}}/>
</span>
\end
<$macrocall $name="tag-body" colour={{!!color}} palette={{$:/palette}}/>

View File

@@ -0,0 +1,113 @@
created: 20220830224607117
modified: 20220830224638865
tags: $:/tags/Macro
title: $:/core/macros/list
\define list-links(filter,type:"ul",subtype:"li",class:"",emptyMessage)
\whitespace trim
<$type$ class="$class$">
<$list filter="$filter$" emptyMessage=<<__emptyMessage__>>>
<$subtype$>
<$link to={{!!title}}>
<$let tv-wikilinks="no">
<$transclude field="caption">
<$view field="title"/>
</$transclude>
</$let>
</$link>
</$subtype$>
</$list>
</$type$>
\end
\define list-links-draggable-drop-actions()
<$action-listops $tiddler=<<targetTiddler>> $field=<<targetField>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/>
\end
\define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate)
\whitespace trim
<span class="tc-links-draggable-list">
<$vars targetTiddler="""$tiddler$""" targetField="""$field$""">
<$type$ class="$class$">
<$list filter="[list[$tiddler$!!$field$]]" emptyMessage=<<__emptyMessage__>>>
<$droppable actions=<<list-links-draggable-drop-actions>> tag="""$subtype$""" enable=<<tv-enable-drag-and-drop>>>
<div class="tc-droppable-placeholder"/>
<div>
<$transclude tiddler="""$itemTemplate$""">
<$link to={{!!title}}>
<$let tv-wikilinks="no">
<$transclude field="caption">
<$view field="title"/>
</$transclude>
</$let>
</$link>
</$transclude>
</div>
</$droppable>
</$list>
<$tiddler tiddler="">
<$droppable actions=<<list-links-draggable-drop-actions>> tag="div" enable=<<tv-enable-drag-and-drop>>>
<div class="tc-droppable-placeholder">
{{$:/core/images/blank}}
</div>
<div style="height:0.5em;"/>
</$droppable>
</$tiddler>
</$type$>
</$vars>
</span>
\end
\define list-tagged-draggable-drop-actions(tag)
\whitespace trim
<!-- Save the current ordering of the tiddlers with this tag -->
<$set name="order" filter="[<__tag__>tagging[]]">
<!-- Remove any list-after or list-before fields from the tiddlers with this tag -->
<$list filter="[<__tag__>tagging[]]">
<$action-deletefield $field="list-before"/>
<$action-deletefield $field="list-after"/>
</$list>
<!-- Save the new order to the Tag Tiddler -->
<$action-listops $tiddler=<<__tag__>> $field="list" $filter="+[enlist<order>] +[insertbefore<actionTiddler>,<currentTiddler>]"/>
<!-- Make sure the newly added item has the right tag -->
<!-- Removing this line makes dragging tags within the dropdown work as intended -->
<!--<$action-listops $tiddler=<<actionTiddler>> $tags=<<__tag__>>/>-->
<!-- Using the following 5 lines as replacement makes dragging titles from outside into the dropdown apply the tag -->
<$list filter="[<actionTiddler>!contains:tags<__tag__>]">
<$fieldmangler tiddler=<<actionTiddler>>>
<$action-sendmessage $message="tm-add-tag" $param=<<__tag__>>/>
</$fieldmangler>
</$list>
</$set>
\end
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"")
\whitespace trim
<span class="tc-tagged-draggable-list">
<$set name="tag" value=<<__tag__>>>
<$list filter="[<__tag__>tagging[]$subFilter$]" emptyMessage=<<__emptyMessage__>> storyview=<<__storyview__>>>
<$elementTag$ class="tc-menu-list-item">
<$droppable actions="""<$macrocall $name="list-tagged-draggable-drop-actions" tag=<<__tag__>>/>""" enable=<<tv-enable-drag-and-drop>>>
<$elementTag$ class="tc-droppable-placeholder"/>
<$elementTag$>
<$transclude tiddler="""$itemTemplate$""">
<$link to={{!!title}}>
<$view field="fr-title">
<$view field="title"/>
</$view>
</$link>
</$transclude>
</$elementTag$>
</$droppable>
</$elementTag$>
</$list>
<$tiddler tiddler="">
<$droppable actions="""<$macrocall $name="list-tagged-draggable-drop-actions" tag=<<__tag__>>/>""" enable=<<tv-enable-drag-and-drop>>>
<$elementTag$ class="tc-droppable-placeholder"/>
<$elementTag$ style="height:0.5em;">
</$elementTag$>
</$droppable>
</$tiddler>
</$set>
</span>
\end

View File

@@ -0,0 +1,39 @@
created: 20220830190922373
modified: 20220830191056761
tags: $:/tags/Macro
title: $:/core/macros/tag
\define tag-pill-styles()
background-color:$(backgroundColor)$;
fill:$(foregroundColor)$;
color:$(foregroundColor)$;
\end
<!-- This has no whitespace trim to avoid modifying $actions$. Closing tags omitted for brevity. -->
\define tag-pill-inner(tag,icon,colour,fallbackTarget,colourA,colourB,element-tag,element-attributes,actions)
<$vars
foregroundColor=<<contrastcolour target:"""$colour$""" fallbackTarget:"""$fallbackTarget$""" colourA:"""$colourA$""" colourB:"""$colourB$""">>
backgroundColor="""$colour$"""
><$element-tag$
$element-attributes$
class="tc-tag-label tc-btn-invisible"
style=<<tag-pill-styles>>
>$actions$<$transclude tiddler="""$icon$"""/><$view tiddler=<<__tag__>> field="fr-title" format="text"><$view tiddler=<<__tag__>> field="title" format="text" /></$view></$element-tag$>
\end
\define tag-pill-body(tag,icon,colour,palette,element-tag,element-attributes,actions)
<$macrocall $name="tag-pill-inner" tag=<<__tag__>> icon="""$icon$""" colour="""$colour$""" fallbackTarget={{$palette$##tag-background}} colourA={{$palette$##foreground}} colourB={{$palette$##background}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/>
\end
\define tag-pill(tag,element-tag:"span",element-attributes:"",actions:"")
\whitespace trim
<span class="tc-tag-list-item" data-tag-title=<<__tag__>>>
<$let currentTiddler=<<__tag__>>>
<$macrocall $name="tag-pill-body" tag=<<__tag__>> icon={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerIconFilter]!is[draft]get[text]] }}} colour={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}} palette={{$:/palette}} element-tag="""$element-tag$""" element-attributes="""$element-attributes$""" actions="""$actions$"""/>
</$let>
</span>
\end
\define tag(tag)
{{$tag$||$:/core/ui/TagTemplate}}
\end

View File

@@ -0,0 +1,25 @@
created: 20220830194301860
modified: 20220830194658750
title: $:/core/ui/TagPickerTagTemplate
\whitespace trim
<$button class=<<button-classes>> tag="a" tooltip={{$:/language/EditTemplate/Tags/Add/Button/Hint}}>
<$list filter="[<saveTiddler>minlength[1]]">
<$action-listops $tiddler=<<saveTiddler>> $field=<<tagField>> $subfilter="[<tag>]"/>
</$list>
<$set name="currentTiddlerCSSEscaped" value={{{ [<saveTiddler>escapecss[]] }}}>
<$action-sendmessage $message="tm-focus-selector" $param=<<get-tagpicker-focus-selector>> preventScroll="true"/>
</$set>
<<delete-tag-state-tiddlers>>
<$list filter="[<refreshTitle>minlength[1]]">
<$action-setfield $tiddler=<<refreshTitle>> text="yes"/>
</$list>
<<actions>>
<$set name="backgroundColor" value={{{ [<currentTiddler>] :cascade[all[shadows+tiddlers]tag[$:/tags/TiddlerColourFilter]!is[draft]get[text]] }}}>
<$wikify name="foregroundColor" text="""<$macrocall $name="contrastcolour" target=<<backgroundColor>> fallbackTarget=<<fallbackTarget>> colourA=<<colourA>> colourB=<<colourB>>/>""">
<span class="tc-tag-label tc-btn-invisible" style=<<tag-pill-styles>>>
{{||$:/core/ui/TiddlerIcon}}<$view field="fr-title" format="text"><$view field="title" format="text"/></$view>
</span>
</$wikify>
</$set>
</$button>

View File

@@ -1,6 +1,6 @@
caption: 5.2.4
created: 20220802100223020
modified: 20220802100223020
modified: 20220902201505817
tags: ReleaseNotes
title: Release 5.2.4
type: text/vnd.tiddlywiki
@@ -11,9 +11,17 @@ type: text/vnd.tiddlywiki
*
! Translation improvements
! Translation improvement
*
Improvements to the following translations:
* Chinese
* Japanese
Improvements to the translation features of TiddlyWiki:
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/6882">> the [[Translators Edition|Translate TiddlyWiki into your language]] to add an option to display the original English text underneath the text area
* <<.link-badge-updated "https://github.com/Jermolene/TiddlyWiki5/pull/6933">> "delete" button text in $:/AdvancedSearch so that it is translatable
! Accessibility Improvements
@@ -21,11 +29,12 @@ type: text/vnd.tiddlywiki
! Usability Improvements
*
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/d62a16ee464fb9984b766b48504829a1a3eb143b">> problem with long presses on tiddler links triggering a preview on iOS/iPadOS
* <<.link-badge-improved "https://github.com/Jermolene/TiddlyWiki5/pull/6910">> consistency of button and input elements across browsers
! Widget Improvements
*
* <<.link-badge-fixed "https://github.com/Jermolene/TiddlyWiki5/commit/127f660c91020dcbb43897d954066b31af729e74">> EditTextWidget to remove the default text "Type the text for the tiddler 'foo'"
! Filter improvements
@@ -33,7 +42,7 @@ type: text/vnd.tiddlywiki
! Hackability Improvements
*
* <<.link-badge-added "https://github.com/Jermolene/TiddlyWiki5/pull/6936">> new operators for reading and formatting JSON data: [[jsonget Operator]], [[jsonindexes Operator]], [[jsontype Operator]] and [[format Operator]]
! Bug Fixes
@@ -56,4 +65,10 @@ type: text/vnd.tiddlywiki
[[@Jermolene|https://github.com/Jermolene]] would like to thank the contributors to this release who have generously given their time to help improve TiddlyWiki:
<<.contributors """
BramChen
fu-sen
oflg
pmario
twMat
xcazin
""">>

View File

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

View File

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

View File

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

View File

@@ -234,6 +234,38 @@ Tests the checkbox widget thoroughly.
},
];
// https://github.com/Jermolene/TiddlyWiki5/issues/6871
const listModeTestsWithListField = (
listModeTests
.filter(data => data.widgetText.includes("listField='colors'"))
.map(data => {
const newData = {
...data,
tiddlers: data.tiddlers.map(tiddler => ({...tiddler, list: tiddler.colors, colors: undefined})),
widgetText: data.widgetText.replace("listField='colors'", "listField='list'"),
expectedChange: {
"Colors": { list: data.expectedChange.Colors.colors.split(' ') }
},
}
return newData;
})
);
const listModeTestsWithTagsField = (
listModeTests
.filter(data => data.widgetText.includes("listField='colors'"))
.map(data => {
const newData = {
...data,
tiddlers: data.tiddlers.map(tiddler => ({...tiddler, tags: tiddler.colors, colors: undefined})),
widgetText: data.widgetText.replace("listField='colors'", "listField='tags'"),
expectedChange: {
"Colors": { tags: data.expectedChange.Colors.colors.split(' ') }
},
}
return newData;
})
);
const indexListModeTests = listModeTests.map(data => {
const newData = {...data};
const newName = data.testName.replace('list mode', 'index list mode');
@@ -453,6 +485,8 @@ Tests the checkbox widget thoroughly.
const checkboxTestData = fieldModeTests.concat(
indexModeTests,
listModeTests,
listModeTestsWithListField,
listModeTestsWithTagsField,
indexListModeTests,
filterModeTests,
);
@@ -495,7 +529,7 @@ Tests the checkbox widget thoroughly.
for (const fieldName of Object.keys(change)) {
const expectedValue = change[fieldName];
const fieldValue = tiddler.fields[fieldName];
expect(fieldValue).toBe(expectedValue);
expect(fieldValue).toEqual(expectedValue);
}
}
})

View File

@@ -1,5 +1,5 @@
created: 20220721200137586
modified: 20220721200137586
modified: 20220819200137586
tags: [[Table of Contents]]
title: Code of Conduct
type: text/vnd.tiddlywiki
@@ -17,6 +17,7 @@ These principles guide technical and non-technical decisions, and help contribut
* We recognise that the motivation for sharing and helping is usually for appreciation, and not financial gain, and so we take care to acknowledge and ''thank the people who enrich the community by sharing what they have created''
* While we are united in our interest in TiddlyWiki, we differ in every other conceivable way. We choose to focus on what unites us, and ''avoid unnecessarily mixing contentious topics like religion and politics''
* We treat each other with respect, and start with the assumption that ''others are acting in good faith''
* We avoid discriminatory language
* We try to use our strength as a community to help others
* We avoid responding when angry or upset because we try to de-escalate conflict
* We make sure we critique ideas, not people
@@ -27,4 +28,6 @@ These principles guide technical and non-technical decisions, and help contribut
Our discussions are in English. It is not the first language of many people in the community, nor do we all share the same cultural background and reference points. So we take care to use language that is clear and unambigous, and avoid cultural references or jokes that will not be widely understood.
It is not acceptable to make jokes or other comments that discriminate by race, gender, sexuality, or other protected characteristic.
As an inclusive community, we are committed to making sure that TiddlyWiki is an accessible tool that understands the needs of people with disabilities.

View File

@@ -1,9 +1,9 @@
created: 20141230182901899
modified: 20210106151027090
modified: 20220226205227090
tags: [[Community Editions]] [[Community Plugins]]
title: "GSD5" by Roma Hicks
type: text/vnd.tiddlywiki
url: http://gsd5.tiddlyspot.com/
url: http://gsd5.tiddlyhost.com/
An adaptation of the [[TiddlyWiki powered GTD® system formerly known as MonkeyGTD|http://mgsd.tiddlyspot.com/]] for TiddlyWiki version 5.

View File

@@ -1,16 +1,12 @@
created: 20131129090249275
modified: 20200507203622933
modified: 20220819041016415
tags: [[Working with TiddlyWiki]]
title: GettingStarted
type: text/vnd.tiddlywiki
The easiest way to use TiddlyWiki is to sign up for a free account with [[Tiddlyhost]], an independently run community service:
The easiest way to use ~TiddlyWiki is to sign up for a free account with [[Tiddlyhost|https://tiddlyhost.com/]], an independently run community service. If you find Tiddlyhost useful, please consider [[donation or sponsorship|https://tiddlyhost.com/donate]].
https://tiddlyhost.com/
If you find Tiddlyhost useful, please consider [[donation or sponsorship|https://tiddlyhost.com/donate]].
Click here to download an empty copy of TiddlyWiki: {{$:/editions/tw5.com/snippets/download-empty-button}}
Click here to download an empty copy of ~TiddlyWiki: {{$:/editions/tw5.com/snippets/download-empty-button}}
The next step is to choose a method for saving changes. There's a wide variety of methods available, with different features and limitations. Click on the badge for a method to see more information about it. You can also click on one of the platform filters to restrict the listing to methods that work with that platform.

View File

@@ -0,0 +1,13 @@
created: 20220909094340097
modified: 20220909094340097
title: Hidden Setting: Sync System Tiddlers From Server
tags: [[Hidden Settings]]
<<.from-version "5.1.23">> Determines whether system tiddlers are synced from the server under Node.js. (Note that this is a one-way setting; system tiddlers are always synced //to// the server).
* `no` -- system tiddlers are not synced from the server (default)
* `yes` -- system tiddlers are synced from the server
Engaging sync of system tiddlers means that tiddlers such as $:/StoryList and $:/HistoryList get synced, which can lead to unexpected outcomes when multiple users are connected to the same server at the same time (it means that the story sequence is synced between all the users).
$:/config/SyncSystemTiddlersFromServer

View File

@@ -22,7 +22,7 @@ The new tiddler message is usually generated with the ButtonWidget or ActionSend
! Examples
To make a button that creates new tiddlers tagged "task", create a tiddler called "TaskTemplate" with that tag, and then make your button like this:
To make a button that creates new tiddlers tagged "task", create a tiddler called "~TaskTemplate" with that tag, and then make your button like this:
```
<$button message="tm-new-tiddler" param="TaskTemplate">New Task</$button>

View File

@@ -1,5 +1,5 @@
created: 20140912140651119
modified: 20220401151525812
modified: 20220812144516626
saving-browser: Firefox Chrome Edge [[Internet Explorer]] Safari Opera [[Standalone App]]
saving-os: Windows Mac Linux Android iOS
tags: [[Working with TiddlyWiki]]
@@ -34,7 +34,7 @@ type: text/vnd.tiddlywiki
\end
<$vars stateTiddler=<<qualify "$:/state/gettingstarted">> >
Available methods for saving changes with TiddlyWiki:
Available methods for saving changes with ~TiddlyWiki:
<div class="tc-wrapper-flex">
<div class="tc-saving-sidebar">

View File

@@ -46,21 +46,17 @@ open the ''example edition'' in a new window
<$macrocall $name="copy-to-clipboard-above-right" src=<<__src__>>/>
```
$src$
```
<$codeblock code=<<__src__>>/>
That renders as:
$$$text/vnd.tiddlywiki
$src$
$$$
<$macrocall $name="__src__"/>
... and the underlying HTML is:
$$$text/vnd.tiddlywiki>text/html
$src$
$$$
<$wikify name="html" text=<<__src__>> output="html">
<$codeblock code=<<html>>/>
</$wikify>
</div>
\end
@@ -69,15 +65,12 @@ $$$
<$macrocall $name="copy-to-clipboard-above-right" src=<<__src__>>/>
```
$src$
```
<$codeblock code=<<__src__>>/>
That renders as:
$$$text/vnd.tiddlywiki
$src$
$$$
<$macrocall $name="__src__"/>
</div>
\end

View File

@@ -1,5 +1,5 @@
created: 20181002131215403
modified: 2020031109590546
modified: 20220909094340097
tags: [[WebServer API]]
title: WebServer API: Get All Tiddlers
type: text/vnd.tiddlywiki
@@ -17,6 +17,8 @@ Parameters:
In order to avoid denial of service attacks with malformed filters in the default configuration the only filter that is accepted is the default filter "[all[tiddlers]!is[system]sort[title]]"; attempts to use any other filter will result in an HTTP 403 error.
<<.note "System tiddlers will not be returned by this API unless the [[Hidden Setting: Sync System Tiddlers From Server]] is explicitly switched on by setting $:/config/SyncSystemTiddlersFromServer to `yes`">>
To enable a particular filter, create a tiddler with the title "$:/config/Server/ExternalFilters/" concatenated with the filter text, and the text field set to "yes". For example, the TiddlyWeb plugin includes the following shadow tiddler to enable the filter that it requires:
```

View File

@@ -0,0 +1,29 @@
caption: genesis
created: 20220924140702430
modified: 20220924140702430
tags: Widgets
title: GenesisWidget
type: text/vnd.tiddlywiki
! Introduction
<<.from-version "5.2.4">> The <<.wlink GenesisWidget>> widget allows the dynamic construction of another widget, where the name and attributes of the new widget can be dynamically determined, without needing to be known in advance.
! Content and Attributes
The content of the <<.wlink GenesisWidget>> widget is used as the content of the dynamically created widget.
|!Attribute |!Description |
|$type |The type of widget or element to create (an initial `$` indicates a widget, otherwise an HTML element will be created) |
|$names |An optional filter evaluating to the names of a list of attributes to be applied to the widget |
|$values |An optional filter evaluating to the values corresponding to the list of names specified in `$names` |
|//{other attributes starting with $}// |Other attributes starting with a single dollar sign are reserved for future use |
|//{attributes starting with $$}// |Attributes starting with two dollar signs are appplied as attributes to the output widget, but with the attribute name changed to use a single dollar sign |
|//{attributes not starting with $}// |Any other attributes that do not start with a dollar are applied as attributes to the output widget |
Note that attributes explicitly specified take precedence over attributes with the same name specified in the `$names` filter.
! Examples
<$macrocall $name='wikitext-example-without-html'
src='<$genesis $type="div" class="tc-thing" label="Squeak">Mouse</$genesis>'/>

View File

@@ -497,3 +497,5 @@ Nolan Darilek, @NDarilek, 2022/06/21
Keiichi Shiga (🎈 BALLOON | FU-SEN), @fu-sen. 2022/07/07
Nathaniel Knight, @nathanielknight, 2022/07/26
HuanCheng Bai, @bestony, 2022/09/17

View File

@@ -3,121 +3,13 @@ tags: $:/tags/EditPreview
list-after: $:/core/ui/EditTemplate/body/preview/output
caption: parse tree
\whitespace trim
\procedure preview-node-properties(node)
<$let excludeProperties="text type tag children attributes orderedAttributes">
<$list filter="[<node>jsonindexes[]] -[subfilter<excludeProperties>] +[limit[1]]" variable="ignore">
<table>
<tbody>
<$list filter="[<node>jsonindexes[]] -[subfilter<excludeProperties>] +[sort[]]" variable="index">
<tr>
<td>
<$text text=<<index>>/>
</td>
<td>
<$text text={{{ [<node>jsonget<index>] }}}/>
</td>
</tr>
</$list>
</tbody>
</table>
</$list>
</$let>
\end
\procedure preview-node-attribute-string(attribute)
<$text text={{{ [<attribute>jsonget[value]] }}}/>
\end
\procedure preview-node-attribute-indirect(attribute)
{{<$text text={{{ [<attribute>jsonget[textReference]] }}}/>}}
\end
\procedure preview-node-attribute-macro(attribute)
&lt;&lt;
<$text text={{{ [<attribute>jsonget[value],[name]] }}}/>
<$list filter="[<attribute>jsonindexes[value],[params]]" variable="index">
&nbsp;
<$list filter="[<attribute>jsonget[value],[params],<index>,[name]]" variable="ignore">
<$text text={{{ [<attribute>jsonget[value],[params],<index>,[name]] }}}/>
:
</$list>
<$text text={{{ [<attribute>jsonget[value],[params],<index>,[value]] }}}/>
</$list>
>>
\end
\procedure preview-node-attributes(node)
<$list filter="[<node>jsonindexes[attributes]limit[1]]" variable="ignore">
<table>
<tbody>
<$list filter="[<node>jsonindexes[attributes]sort[]]" variable="index">
<tr>
<td>
<$text text=<<index>>/>
</td>
<td>
<$let type={{{ [<node>jsonget[attributes],<index>,[type]] }}}>
<$transclude $variable={{{ [<type>match[string]then[preview-node-attribute-string]] :else[<type>match[indirect]then[preview-node-attribute-indirect]] :else[<type>match[macro]then[preview-node-attribute-macro]] }}} attribute={{{ [<node>jsonget[attributes],<index>] }}}/>
</$let>
</td>
</tr>
</$list>
</tbody>
</table>
</$list>
\end
\procedure preview-node-children(node)
<div style="padding:4px 4px 0 4px;">
<$transclude $variable="preview-node-properties" node=<<node>>/>
<$transclude $variable="preview-node-attributes" node=<<node>>/>
<$transclude $variable="preview-node-list" nodeList={{{ [<node>jsonget[children]] }}}/>
</div>
\end
\procedure preview-node-title-widget(node)
<div style="border:2px solid red;margin:4px;">
<div style="background:red;color:white;padding:4px;">
<$<$text text={{{ [<node>jsonget[type]] }}}/>>
</div>
<$transclude $variable="preview-node-children" node=<<node>>/>
</div>
\end
\procedure preview-node-title-element(node)
<div style="border:2px solid purple;margin:4px;">
<div style="background:purple;color:white;padding:4px;">
&lt;<$text text={{{ [<node>jsonget[tag]] }}}/>>
</div>
<$transclude $variable="preview-node-children" node=<<node>>/>
</div>
\end
\procedure preview-node-title-text(node)
<div style="border:2px solid green;margin:4px;">
<div style="background:green;color:white;padding:4px;">
<span style="color:#ff0;font-weight:bold;">"</span><span style="white-space:pre-wrap;"><$text text={{{ [<node>jsonget[text]] }}}/></span><span style="color:#ff0;font-weight:bold;">"</span>
</div>
</div>
\end
\procedure preview-node(node)
<$let type={{{ [<node>jsonget[type]] }}}>
<$transclude $variable={{{ [<type>match[element]then[preview-node-title-element]] :else[<type>match[text]then[preview-node-title-text]] :else[[preview-node-title-widget]] }}} node=<<node>>/>
</$let>
\end
\procedure preview-node-list(nodeList)
<$list filter="[<nodeList>jsonindexes[]]" variable="index">
<$transclude $variable="preview-node" node={{{ [<nodeList>jsonget<index>] }}}/>
</$list>
\end
\procedure preview(mode)
<$wikify name="preview-json" text={{!!text}} type={{!!type}} mode=<<mode>> output="parsetree">
<$transclude $variable="preview-node-list" nodeList=<<preview-json>>/>
\define preview(mode)
<$wikify name="preview-text" text={{!!text}} type={{!!type}} mode="$mode$" output="parsetree">
<pre>
<code>
<$text text=<<preview-text>>/>
</code>
</pre>
</$wikify>
\end

View File

@@ -0,0 +1,93 @@
/*\
title: $:/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js
type: application/javascript
tags: [[$:/tags/test-spec]]
Tests the wiki based tests
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var TEST_WIKI_TIDDLER_FILTER = "[type[text/vnd.tiddlywiki-multiple]tag[$:/tags/wiki-test-spec]]";
var widget = require("$:/core/modules/widgets/widget.js");
describe("Wiki-based tests", function() {
// Step through the test tiddlers
var tests = $tw.wiki.filterTiddlers(TEST_WIKI_TIDDLER_FILTER);
$tw.utils.each(tests,function(title) {
var tiddler = $tw.wiki.getTiddler(title);
it(tiddler.fields.title + ": " + tiddler.fields.description, function() {
// Add our tiddlers
var wiki = new $tw.Wiki();
wiki.addTiddlers(readMultipleTiddlersTiddler(title));
// Complain if we don't have the ouput and expected results
if(!wiki.tiddlerExists("Output")) {
throw "Missing 'Output' tiddler";
}
if(!wiki.tiddlerExists("ExpectedResult")) {
throw "Missing 'ExpectedResult' tiddler";
}
// Construct the widget node
var text = "{{Output}}\n\n";
var widgetNode = createWidgetNode(parseText(text,wiki),wiki);
// Render the widget node to the DOM
var wrapper = renderWidgetNode(widgetNode);
// Clear changes queue
wiki.clearTiddlerEventQueue();
// Run the actions if provided
if(wiki.tiddlerExists("Actions")) {
widgetNode.invokeActionString(wiki.getTiddlerText("Actions"));
refreshWidgetNode(widgetNode,wrapper);
}
// Test the rendering
expect(wrapper.innerHTML).toBe(wiki.getTiddlerText("ExpectedResult"));
});
});
function readMultipleTiddlersTiddler(title) {
var rawTiddlers = $tw.wiki.getTiddlerText(title).split("\n+\n");
var tiddlers = [];
$tw.utils.each(rawTiddlers,function(rawTiddler) {
var fields = Object.create(null),
split = rawTiddler.split(/\r?\n\r?\n/mg);
if(split.length >= 1) {
fields = $tw.utils.parseFields(split[0],fields);
}
if(split.length >= 2) {
fields.text = split.slice(1).join("\n\n");
}
tiddlers.push(fields);
});
return tiddlers;
}
function createWidgetNode(parser,wiki) {
return wiki.makeWidget(parser);
}
function parseText(text,wiki,options) {
return wiki.parseText("text/vnd.tiddlywiki",text,options);
}
function renderWidgetNode(widgetNode) {
$tw.fakeDocument.setSequenceNumber(0);
var wrapper = $tw.fakeDocument.createElement("div");
widgetNode.render(wrapper,null);
// console.log(require("util").inspect(wrapper,{depth: 8}));
return wrapper;
}
function refreshWidgetNode(widgetNode,wrapper) {
widgetNode.refresh(widgetNode.wiki.changedTiddlers,wrapper);
// console.log(require("util").inspect(wrapper,{depth: 8}));
}
});
})();