1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-22 09:59:50 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Jeremy Ruston
88619fc215 Add changenote 2025-12-29 21:09:17 +00:00
Jeremy Ruston
dfc5e9e6e5 Initial Commit 2025-12-29 21:01:38 +00:00
157 changed files with 2856 additions and 2818 deletions

View File

@@ -1,62 +0,0 @@
---
name: Bug report
about: Create a report to help us improve TiddlyWiki 5
title: "[Report] "
type: report
---
<!-- Remove elements, that you do not need -->
<!-- Add screenshots where needed -->
**Problem Description**
<!-- Describe your problem: A clear and concise description of what your problem is -->
**To Reproduce**
Steps to reproduce the behavior:
1. At https://tiddlywiki.com
2. Click on ...
3. Scroll down to ...
4. See ...
**Expected behavior**
As a user,
<!-- As a developer, -->
I would expect ...
**TiddlyWiki Configuration**
<!-- Please complete the following information -->
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
<!-- Your report comes here -->
<!-- or -->
<!-- Add it manually -->
- Version: <!-- e.g. v5.3.8 -->
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
**Desktop**
<!-- Please complete the following information -->
- OS: <!-- e.g. iOS -->
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
**Smartphone**
<!-- Please complete the following information -->
- Device: <!-- e.g. iPhone6 -->
- OS: <!-- e.g. iOS8.1 -->
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
**Additional context**
<!-- Add any other context about the problem here. -->

68
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,68 @@
name: Bug report
description: Create a report to help us improve TiddlyWiki 5
title: "[BUG] "
type: bug
body:
- type: textarea
id: Describe
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: Expected
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: false
- type: textarea
id: Reproduce
attributes:
label: To Reproduce
description: "Steps to reproduce the behavior:"
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: false
- type: textarea
id: Screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
placeholder: Drag image here to upload screenshot!
validations:
required: false
- type: textarea
id: Configuration
attributes:
label: TiddlyWiki Configuration
description: please complete the following information
placeholder: |
- Version [e.g. v5.1.24]
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
- Plugins installed [e.g. Freelinks, TiddlyMap]
### Desktop (please complete the following information):
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
### Smartphone (please complete the following information):
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
validations:
required: true
- type: textarea
id: Context
attributes:
label: Additional context
description: Add any other context about the problem here.

View File

@@ -4,23 +4,18 @@ about: Suggest an idea for TiddlyWiki 5
title: "[IDEA]" title: "[IDEA]"
labels: '' labels: ''
assignees: '' assignees: ''
type: idea type: feature
--- ---
**Is your idea related to a problem? Please describe.** **Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is. Eg:
As a user, I would like [...]
**Describe the solution you'd like** **Describe the solution you'd like**
A clear and concise description of what you want to happen. A clear and concise description of what you want to happen.
**Describe alternatives you've considered** **Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered. A clear and concise description of any alternative solutions or features you've considered.
**Additional context** **Additional context**
Add any other context or screenshots about the feature request here. Add any other context or screenshots about the feature request here.

View File

@@ -1,30 +0,0 @@
/*\
title: $:/core-modules/modules/utils/base64.js
type: application/javascript
module-type: utils-node
Base64 UTF-8 utlity functions.
\*/
"use strict";
const{ TextEncoder, TextDecoder } = require("node:util");
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
function base64ToBytes(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, m => m.codePointAt(0));
};
function bytesToBase64(bytes) {
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));

View File

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

View File

@@ -5,4 +5,3 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]] * [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]] * [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]] * [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
* [[diff-match-patch-es by antfu|https://github.com/antfu/diff-match-patch-es]]

View File

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

View File

@@ -14,31 +14,31 @@ Export our filter function
*/ */
exports.sort = function(source,operator,options) { exports.sort = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
return results; return results;
}; };
exports.nsort = function(source,operator,options) { exports.nsort = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
return results; return results;
}; };
exports.sortan = function(source, operator, options) { exports.sortan = function(source, operator, options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]); options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
return results; return results;
}; };
exports.sortcs = function(source,operator,options) { exports.sortcs = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
return results; return results;
}; };
exports.nsortcs = function(source,operator,options) { exports.nsortcs = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
return results; return results;
}; };

View File

@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
operand = (operator.operand || ""), operand = (operator.operand || ""),
fnCalc; fnCalc;
if(suffix === "prefix") { if(suffix === "prefix") {
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}; fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
} else if(suffix === "suffix") { } else if(suffix === "suffix") {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}; fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
} else { } else {
if(operand === "") { if(operand === "") {
fnCalc = function(a) {return [$tw.utils.trim(a)];}; fnCalc = function(a) {return [$tw.utils.trim(a)];}
} else { } else {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}; fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
} }
} }
source(function(tiddler,title) { source(function(tiddler,title) {
@@ -71,53 +71,107 @@ exports.join = makeStringReducingOperator(
},null },null
); );
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js"); var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
exports.levenshtein = makeStringBinaryOperator( exports.levenshtein = makeStringBinaryOperator(
function(a,b) { function(a,b) {
const diffs = dmp.diffMain(a,b); var dmpObject = new dmp.diff_match_patch(),
return [dmp.diffLevenshtein(diffs).toString()]; diffs = dmpObject.diff_main(a,b);
return [dmpObject.diff_levenshtein(diffs) + ""];
} }
); );
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs // these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode) { function diffLineWordMode(text1,text2,mode) {
var a = $tw.utils.diffPartsToChars(text1,text2,mode); var dmpObject = new dmp.diff_match_patch();
var a = diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1; var lineText1 = a.chars1;
var lineText2 = a.chars2; var lineText2 = a.chars2;
var lineArray = a.lineArray; var lineArray = a.lineArray;
var diffs = dmp.diffMain(lineText1,lineText2,false); var diffs = dmpObject.diff_main(lineText1,lineText2,false);
dmp.diffCharsToLines(diffs,lineArray); dmpObject.diff_charsToLines_(diffs,lineArray);
return diffs; return diffs;
} }
function diffPartsToChars(text1,text2,mode) {
var lineArray = [];
var lineHash = {};
lineArray[0] = '';
function diff_linesToPartsMunge_(text,mode) {
var chars = '';
var lineStart = 0;
var lineEnd = -1;
var lineArrayLength = lineArray.length,
regexpResult;
var searchRegexp = /\W+/g;
while(lineEnd < text.length - 1) {
if(mode === "words") {
regexpResult = searchRegexp.exec(text);
lineEnd = searchRegexp.lastIndex;
if(regexpResult === null) {
lineEnd = text.length;
}
lineEnd = --lineEnd;
} else {
lineEnd = text.indexOf('\n', lineStart);
if(lineEnd == -1) {
lineEnd = text.length - 1;
}
}
var line = text.substring(lineStart, lineEnd + 1);
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
chars += String.fromCharCode(lineHash[line]);
} else {
if(lineArrayLength == maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
var maxLines = 40000;
var chars1 = diff_linesToPartsMunge_(text1,mode);
maxLines = 65535;
var chars2 = diff_linesToPartsMunge_(text2,mode);
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
};
exports.makepatches = function(source,operator,options) { exports.makepatches = function(source,operator,options) {
var suffix = operator.suffix || "", var dmpObject = new dmp.diff_match_patch(),
suffix = operator.suffix || "",
result = []; result = [];
source(function(tiddler,title) { source(function(tiddler,title) {
let diffs, patches; var diffs, patches;
if(suffix === "lines" || suffix === "words") { if(suffix === "lines" || suffix === "words") {
diffs = diffLineWordMode(title,operator.operand,suffix); diffs = diffLineWordMode(title,operator.operand,suffix);
patches = dmp.patchMake(title,diffs); patches = dmpObject.patch_make(title,diffs);
} else { } else {
patches = dmp.patchMake(title,operator.operand); patches = dmpObject.patch_make(title,operator.operand);
} }
Array.prototype.push.apply(result,[dmp.patchToText(patches)]); Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
}); });
return result; return result;
}; };
exports.applypatches = makeStringBinaryOperator( exports.applypatches = makeStringBinaryOperator(
function(a,b) { function(a,b) {
let patches; var dmpObject = new dmp.diff_match_patch(),
patches;
try { try {
patches = dmp.patchFromText(b); patches = dmpObject.patch_fromText(b);
} catch(e) { } catch(e) {
} }
if(patches) { if(patches) {
return [dmp.patchApply(patches,a)[0]]; return [dmpObject.patch_apply(patches,a)[0]];
} else { } else {
return [a]; return [a];
} }
@@ -225,7 +279,7 @@ exports.pad = function(source,operator,options) {
} }
}); });
return results; return results;
}; }
exports.charcode = function(source,operator,options) { exports.charcode = function(source,operator,options) {
var chars = []; var chars = [];

View File

@@ -11,16 +11,17 @@ The image parser parses an image into an embeddable HTML element
var ImageParser = function(type,text,options) { var ImageParser = function(type,text,options) {
var element = { var element = {
type: "image", type: "element",
attributes: {} tag: "img",
}; attributes: {}
};
if(options._canonical_uri) { if(options._canonical_uri) {
element.attributes.source = {type: "string", value: options._canonical_uri}; element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) { } else if(text) {
if(type === "image/svg+xml" || type === ".svg") { if(type === "image/svg+xml" || type === ".svg") {
element.attributes.source = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)}; element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
} else { } else {
element.attributes.source = {type: "string", value: "data:" + type + ";base64," + text}; element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
} }
} }
this.tree = [element]; this.tree = [element];

View File

@@ -18,6 +18,7 @@ exports.synchronous = true;
// Default story and history lists // Default story and history lists
var PAGE_TITLE_TITLE = "$:/core/wiki/title"; var PAGE_TITLE_TITLE = "$:/core/wiki/title";
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet"; var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
var ROOT_STYLESHEET_TITLE = "$:/core/ui/RootStylesheet";
var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate"; var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate";
// Time (in ms) that we defer refreshing changes to draft tiddlers // Time (in ms) that we defer refreshing changes to draft tiddlers
@@ -44,22 +45,13 @@ exports.startup = function() {
publishTitle(); publishTitle();
} }
}); });
// Set up the styles
$tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument}); var styleParser = $tw.wiki.parseTiddler(ROOT_STYLESHEET_TITLE,{parseAsInline: true}),
$tw.styleContainer = $tw.fakeDocument.createElement("style"); styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: document});
$tw.styleWidgetNode.render($tw.styleContainer,null); styleWidgetNode.render(document.head,null);
$tw.styleWidgetNode.assignedStyles = $tw.styleContainer.textContent;
$tw.styleElement = document.createElement("style");
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
document.head.insertBefore($tw.styleElement,document.head.firstChild);
$tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) { $tw.wiki.addEventListener("change",$tw.perf.report("styleRefresh",function(changes) {
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,null)) { styleWidgetNode.refresh(changes,document.head,null);
var newStyles = $tw.styleContainer.textContent;
if(newStyles !== $tw.styleWidgetNode.assignedStyles) {
$tw.styleWidgetNode.assignedStyles = newStyles;
$tw.styleElement.innerHTML = $tw.styleWidgetNode.assignedStyles;
}
}
})); }));
// Display the $:/core/ui/PageTemplate tiddler to kick off the display // Display the $:/core/ui/PageTemplate tiddler to kick off the display
$tw.perf.report("mainRender",function() { $tw.perf.report("mainRender",function() {
@@ -68,7 +60,7 @@ exports.startup = function() {
$tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper"); $tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper");
document.body.insertBefore($tw.pageContainer,document.body.firstChild); document.body.insertBefore($tw.pageContainer,document.body.firstChild);
$tw.pageWidgetNode.render($tw.pageContainer,null); $tw.pageWidgetNode.render($tw.pageContainer,null);
$tw.hooks.invokeHook("th-page-refreshed"); $tw.hooks.invokeHook("th-page-refreshed");
})(); })();
// Remove any splash screen elements // Remove any splash screen elements
var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded"); var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded");

View File

@@ -63,24 +63,16 @@ exports.startup = function() {
$tw.eventBus.emit("window:closed",{windowID}); $tw.eventBus.emit("window:closed",{windowID});
},false); },false);
// Set up the styles // Set up the styles
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{ var styleParser = $tw.wiki.parseTiddler("$:/core/ui/RootStylesheet",{parseAsInline: true}),
document: $tw.fakeDocument, styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: srcDocument});
variables: variables, styleWidgetNode.render(srcDocument.head,null);
importPageMacros: true}),
styleContainer = $tw.fakeDocument.createElement("style");
styleWidgetNode.render(styleContainer,null);
var styleElement = srcDocument.createElement("style");
styleElement.innerHTML = styleContainer.textContent;
srcDocument.head.insertBefore(styleElement,srcDocument.head.firstChild);
// Render the text of the tiddler // Render the text of the tiddler
var parser = $tw.wiki.parseTiddler(template), var parser = $tw.wiki.parseTiddler(template),
widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: variables}); widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: variables});
widgetNode.render(srcDocument.body,srcDocument.body.firstChild); widgetNode.render(srcDocument.body,srcDocument.body.firstChild);
// Function to handle refreshes // Function to handle refreshes
refreshHandler = function(changes) { refreshHandler = function(changes) {
if(styleWidgetNode.refresh(changes,styleContainer,null)) { styleWidgetNode.refresh(changes);
styleElement.innerHTML = styleContainer.textContent;
}
widgetNode.refresh(changes); widgetNode.refresh(changes);
}; };
$tw.wiki.addEventListener("change",refreshHandler); $tw.wiki.addEventListener("change",refreshHandler);

View File

@@ -1,31 +0,0 @@
/*\
title: $:/core/modules/utils/base64.js
type: application/javascript
module-type: utils-browser
Base64 utility functions
\*/
"use strict";
/*
Base64 utility functions that work in either browser or Node.js
*/
exports.btoa = binstr => window.btoa(binstr);
exports.atob = b64 => window.atob(b64);
function base64ToBytes(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, m => m.codePointAt(0));
};
function bytesToBase64(bytes) {
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));

View File

@@ -44,15 +44,15 @@ exports.domMatchesSelector = (node,selector) => node.matches(selector);
exports.hasClass = (el,className) => el.classList && el.classList.contains(className); exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
exports.addClass = function(el,className) { exports.addClass = function(el,className) {
el.classList && className && el.classList.add(className); el.classList && el.classList.add(className);
}; };
exports.removeClass = function(el,className) { exports.removeClass = function(el,className) {
el.classList && className && el.classList.remove(className); el.classList && el.classList.remove(className);
}; };
exports.toggleClass = function(el,className,status) { exports.toggleClass = function(el,className,status) {
el.classList && className && el.classList.toggle(className, status); el.classList && el.classList.toggle(className, status);
}; };
exports.getLocationPath = () => window.location.origin + window.location.pathname; exports.getLocationPath = () => window.location.origin + window.location.pathname;

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -9,8 +9,6 @@ Button widget
"use strict"; "use strict";
const ALLOWED_SELECTED_ARIA_ATTR = ["aria-checked", "aria-selected", "aria-pressed"];
var Widget = require("$:/core/modules/widgets/widget.js").widget; var Widget = require("$:/core/modules/widgets/widget.js").widget;
var Popup = require("$:/core/modules/utils/dom/popup.js"); var Popup = require("$:/core/modules/utils/dom/popup.js");
@@ -46,14 +44,9 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
var classes = this["class"].split(" ") || [], var classes = this["class"].split(" ") || [],
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp(); isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
if(this.selectedClass) { if(this.selectedClass) {
if((this.set || this.setTitle) && this.setTo) { if((this.set || this.setTitle) && this.setTo && this.isSelected()) {
const selectedAria = ALLOWED_SELECTED_ARIA_ATTR.includes(this.selectedAria) ? this.selectedAria : "aria-checked"; $tw.utils.pushTop(classes, this.selectedClass.split(" "));
if(this.isSelected()) { domNode.setAttribute("aria-checked", "true");
$tw.utils.pushTop(classes, this.selectedClass.split(" "));
domNode.setAttribute(selectedAria, "true");
} else {
domNode.setAttribute(selectedAria, "false");
}
} }
if(isPoppedUp) { if(isPoppedUp) {
$tw.utils.pushTop(classes,this.selectedClass.split(" ")); $tw.utils.pushTop(classes,this.selectedClass.split(" "));
@@ -228,7 +221,6 @@ ButtonWidget.prototype.execute = function() {
this.style = this.getAttribute("style"); this.style = this.getAttribute("style");
this["class"] = this.getAttribute("class",""); this["class"] = this.getAttribute("class","");
this.selectedClass = this.getAttribute("selectedClass"); this.selectedClass = this.getAttribute("selectedClass");
this.selectedAria = this.getAttribute("selectedAria");
this.defaultSetValue = this.getAttribute("default",""); this.defaultSetValue = this.getAttribute("default","");
this.buttonTag = this.getAttribute("tag"); this.buttonTag = this.getAttribute("tag");
this.dragTiddler = this.getAttribute("dragTiddler"); this.dragTiddler = this.getAttribute("dragTiddler");

View File

@@ -9,8 +9,8 @@ Widget to display a diff between two texts
"use strict"; "use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget; var Widget = require("$:/core/modules/widgets/widget.js").widget,
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js"); dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
var DiffTextWidget = function(parseTreeNode,options) { var DiffTextWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options); this.initialise(parseTreeNode,options);
@@ -35,24 +35,19 @@ DiffTextWidget.prototype.render = function(parent,nextSibling) {
this.computeAttributes(); this.computeAttributes();
this.execute(); this.execute();
// Create the diff object // Create the diff object
const editCost = $tw.utils.parseNumber(this.getAttribute("editcost","4")); var dmpObject = new dmp.diff_match_patch();
const mode = this.getAttribute("mode") || "chars"; dmpObject.Diff_EditCost = $tw.utils.parseNumber(this.getAttribute("editcost","4"));
let diffs; var diffs = dmpObject.diff_main(this.getAttribute("source",""),this.getAttribute("dest",""));
if(mode === "lines" || mode === "words") {
diffs = diffLineWordMode(this.getAttribute("source",""),this.getAttribute("dest",""),mode,editCost);
} else {
diffs = dmp.diffMain(this.getAttribute("source",""),this.getAttribute("dest",""),{diffEditCost: editCost});
}
// Apply required cleanup // Apply required cleanup
switch(this.getAttribute("cleanup","semantic")) { switch(this.getAttribute("cleanup","semantic")) {
case "none": case "none":
// No cleanup // No cleanup
break; break;
case "efficiency": case "efficiency":
dmp.diffCleanupEfficiency(diffs, {diffEditCost: editCost}); dmpObject.diff_cleanupEfficiency(diffs);
break; break;
default: // case "semantic" default: // case "semantic"
dmp.diffCleanupSemantic(diffs); dmpObject.diff_cleanupSemantic(diffs);
break; break;
} }
// Create the elements // Create the elements
@@ -138,7 +133,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
*/ */
DiffTextWidget.prototype.refresh = function(changedTiddlers) { DiffTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes(); var changedAttributes = this.computeAttributes();
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.mode || changedAttributes.editcost) { if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.editcost) {
this.refreshSelf(); this.refreshSelf();
return true; return true;
} else { } else {
@@ -146,15 +141,4 @@ DiffTextWidget.prototype.refresh = function(changedTiddlers) {
} }
}; };
// This function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode,editCost) {
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1;
var lineText2 = a.chars2;
var lineArray = a.lineArray;
var diffs = dmp.diffMain(lineText1,lineText2,{diffEditCost: editCost});
dmp.diffCharsToLines(diffs,lineArray);
return diffs;
}
exports["diff-text"] = DiffTextWidget; exports["diff-text"] = DiffTextWidget;

View File

@@ -25,6 +25,7 @@ Render this widget into the DOM
*/ */
ElementWidget.prototype.render = function(parent,nextSibling) { ElementWidget.prototype.render = function(parent,nextSibling) {
this.parentDomNode = parent; this.parentDomNode = parent;
this.computeAttributes();
// Neuter blacklisted elements // Neuter blacklisted elements
this.tag = this.parseTreeNode.tag; this.tag = this.parseTreeNode.tag;
if($tw.config.htmlUnsafeElements.indexOf(this.tag) !== -1) { if($tw.config.htmlUnsafeElements.indexOf(this.tag) !== -1) {
@@ -41,8 +42,6 @@ ElementWidget.prototype.render = function(parent,nextSibling) {
headingLevel = Math.min(Math.max(headingLevel + 1 + baseLevel,1),6); headingLevel = Math.min(Math.max(headingLevel + 1 + baseLevel,1),6);
this.tag = "h" + headingLevel; this.tag = "h" + headingLevel;
} }
// Compute the attributes, mapping the element tag if needed
this.computeAttributes();
// Select the namespace for the tag // Select the namespace for the tag
var XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml", var XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml",
tagNamespaces = { tagNamespaces = {
@@ -100,25 +99,4 @@ ElementWidget.prototype.refresh = function(changedTiddlers) {
return this.refreshChildren(changedTiddlers) || hasChangedAttributes; return this.refreshChildren(changedTiddlers) || hasChangedAttributes;
}; };
/*
Override the base computeAttributes method
*/
ElementWidget.prototype.computeAttributes = function() {
// Call the base class to compute the initial values of the attributes
var changedAttributes = Widget.prototype.computeAttributes.call(this);
// Check for element mapping
var mappedTag = this.getVariable("tv-map-" + this.tag),
mappedClass = this.getVariable("tv-map-" + this.tag + "-class");
if(mappedTag) {
this.tag = mappedTag.trim();
// Add an attribute to indicate the original tag
this.attributes["data-element-mapping-from"] = this.parseTreeNode.tag;
// Check for a mapped class
if(mappedClass) {
this.attributes["class"] = mappedClass.trim() + (this.attributes["class"] ? " " + this.attributes["class"] : "");
}
}
return changedAttributes;
};
exports.element = ElementWidget; exports.element = ElementWidget;

View File

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

View File

@@ -9,215 +9,376 @@ View widget
"use strict"; "use strict";
var Widget = require("$:/core/modules/widgets/widget.js").widget; const Widget = require("$:/core/modules/widgets/widget.js").widget;
var ViewWidget = function(parseTreeNode,options) {
this.initialise(parseTreeNode,options);
};
/* /*
Inherit from the base widget class ==========================================
ViewHandler Base Class
==========================================
Base class for all view format handlers.
Provides common functionality and defines the interface for subclasses.
*/ */
ViewWidget.prototype = new Widget(); class ViewHandler {
constructor(widget) {
/* this.widget = widget;
Render this widget into the DOM this.wiki = widget.wiki;
*/ this.document = widget.document;
ViewWidget.prototype.render = function(parent,nextSibling) { this.viewTitle = widget.viewTitle;
this.parentDomNode = parent; this.viewField = widget.viewField;
this.computeAttributes(); this.viewIndex = widget.viewIndex;
this.execute(); this.viewSubtiddler = widget.viewSubtiddler;
if(this.text) { this.viewTemplate = widget.viewTemplate;
var textNode = this.document.createTextNode(this.text); this.viewMode = widget.viewMode;
parent.insertBefore(textNode,nextSibling);
this.domNodes.push(textNode);
} else {
this.makeChildWidgets();
this.renderChildren(parent,nextSibling);
} }
};
/* render(parent, nextSibling) {
Compute the internal state of the widget this.text = this.getValue();
*/ this.createTextNode(parent, nextSibling);
ViewWidget.prototype.execute = function() {
// Get parameters from our attributes
this.viewTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
this.viewSubtiddler = this.getAttribute("subtiddler");
this.viewField = this.getAttribute("field","text");
this.viewIndex = this.getAttribute("index");
this.viewFormat = this.getAttribute("format","text");
this.viewTemplate = this.getAttribute("template","");
this.viewMode = this.getAttribute("mode","block");
switch(this.viewFormat) {
case "htmlwikified":
this.text = this.getValueAsHtmlWikified(this.viewMode);
break;
case "plainwikified":
this.text = this.getValueAsPlainWikified(this.viewMode);
break;
case "htmlencodedplainwikified":
this.text = this.getValueAsHtmlEncodedPlainWikified(this.viewMode);
break;
case "htmlencoded":
this.text = this.getValueAsHtmlEncoded();
break;
case "htmltextencoded":
this.text = this.getValueAsHtmlTextEncoded();
break;
case "urlencoded":
this.text = this.getValueAsUrlEncoded();
break;
case "doubleurlencoded":
this.text = this.getValueAsDoubleUrlEncoded();
break;
case "date":
this.text = this.getValueAsDate(this.viewTemplate);
break;
case "relativedate":
this.text = this.getValueAsRelativeDate();
break;
case "stripcomments":
this.text = this.getValueAsStrippedComments();
break;
case "jsencoded":
this.text = this.getValueAsJsEncoded();
break;
default: // "text"
this.text = this.getValueAsText();
break;
} }
};
/* getValue() {
The various formatter functions are baked into this widget for the moment. Eventually they will be replaced by macro functions return this.widget.getValueAsText();
*/ }
/* createTextNode(parent, nextSibling) {
Retrieve the value of the widget. Options are: if(this.text) {
asString: Optionally return the value as a string const textNode = this.document.createTextNode(this.text);
*/ parent.insertBefore(textNode, nextSibling);
ViewWidget.prototype.getValue = function(options) { this.widget.domNodes.push(textNode);
options = options || {};
var value = options.asString ? "" : undefined;
if(this.viewIndex) {
value = this.wiki.extractTiddlerDataItem(this.viewTitle,this.viewIndex);
} else {
var tiddler;
if(this.viewSubtiddler) {
tiddler = this.wiki.getSubTiddler(this.viewTitle,this.viewSubtiddler);
} else { } else {
tiddler = this.wiki.getTiddler(this.viewTitle); this.widget.makeChildWidgets();
} this.widget.renderChildren(parent, nextSibling);
if(tiddler) {
if(this.viewField === "text" && !this.viewSubtiddler) {
// Calling getTiddlerText() triggers lazy loading of skinny tiddlers
value = this.wiki.getTiddlerText(this.viewTitle);
} else {
if($tw.utils.hop(tiddler.fields,this.viewField)) {
if(options.asString) {
value = tiddler.getFieldString(this.viewField);
} else {
value = tiddler.fields[this.viewField];
}
}
}
} else {
if(this.viewField === "title") {
value = this.viewTitle;
}
} }
} }
return value;
};
ViewWidget.prototype.getValueAsText = function() { refresh() {
return this.getValue({asString: true}); var self = this;
};
ViewWidget.prototype.getValueAsHtmlWikified = function(mode) {
return this.wiki.renderText("text/html","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
});
};
ViewWidget.prototype.getValueAsPlainWikified = function(mode) {
return this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
});
};
ViewWidget.prototype.getValueAsHtmlEncodedPlainWikified = function(mode) {
return $tw.utils.htmlEncode(this.wiki.renderText("text/plain","text/vnd.tiddlywiki",this.getValueAsText(),{
parseAsInline: mode !== "block",
parentWidget: this
}));
};
ViewWidget.prototype.getValueAsHtmlEncoded = function() {
return $tw.utils.htmlEncode(this.getValueAsText());
};
ViewWidget.prototype.getValueAsHtmlTextEncoded = function() {
return $tw.utils.htmlTextEncode(this.getValueAsText());
};
ViewWidget.prototype.getValueAsUrlEncoded = function() {
return $tw.utils.encodeURIComponentExtended(this.getValueAsText());
};
ViewWidget.prototype.getValueAsDoubleUrlEncoded = function() {
return $tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(this.getValueAsText()));
};
ViewWidget.prototype.getValueAsDate = function(format) {
format = format || "YYYY MM DD 0hh:0mm";
var value = $tw.utils.parseDate(this.getValue());
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.formatDateString(value,format);
} else {
return "";
}
};
ViewWidget.prototype.getValueAsRelativeDate = function(format) {
var value = $tw.utils.parseDate(this.getValue());
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.getRelativeDate((new Date()) - (new Date(value))).description;
} else {
return "";
}
};
ViewWidget.prototype.getValueAsStrippedComments = function() {
var lines = this.getValueAsText().split("\n"),
out = [];
for(var line=0; line<lines.length; line++) {
var text = lines[line];
if(!/^\s*\/\/#/.test(text)) {
out.push(text);
}
}
return out.join("\n");
};
ViewWidget.prototype.getValueAsJsEncoded = function() {
return $tw.utils.stringify(this.getValueAsText());
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
ViewWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes.template || changedAttributes.format || changedTiddlers[this.viewTitle]) {
this.refreshSelf();
return true;
} else {
return false; return false;
} }
}
/*
==========================================
Wikified View Handler Base
==========================================
Base class for wikified view handlers
*/
class WikifiedViewHandler extends ViewHandler {
constructor(widget) {
super(widget);
this.fakeWidget = null;
this.fakeNode = null;
}
render(parent, nextSibling) {
this.createFakeWidget();
this.text = this.getValue();
this.createWikifiedTextNode(parent, nextSibling);
}
createFakeWidget() {
this.fakeWidget = this.wiki.makeTranscludeWidget(this.viewTitle, {
document: $tw.fakeDocument,
field: this.viewField,
index: this.viewIndex,
parseAsInline: this.viewMode !== "block",
mode: this.viewMode === "block" ? "block" : "inline",
parentWidget: this.widget,
subTiddler: this.viewSubtiddler
});
this.fakeNode = $tw.fakeDocument.createElement("div");
this.fakeWidget.makeChildWidgets();
this.fakeWidget.render(this.fakeNode, null);
}
createWikifiedTextNode(parent, nextSibling) {
const textNode = this.document.createTextNode(this.text || "");
parent.insertBefore(textNode, nextSibling);
this.widget.domNodes.push(textNode);
}
refresh(changedTiddlers) {
const refreshed = this.fakeWidget.refresh(changedTiddlers);
if(refreshed) {
const newText = this.getValue();
if(newText !== this.text) {
this.widget.domNodes[0].textContent = newText;
this.text = newText;
}
}
return refreshed;
}
}
/*
==========================================
Text View Handler
==========================================
Default handler for plain text display
*/
class TextViewHandler extends ViewHandler {}
/*
==========================================
HTML Wikified View Handler
==========================================
Handler for wikified HTML content
*/
class HTMLWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return this.fakeNode.innerHTML;
}
}
/*
==========================================
Plain Wikified View Handler
==========================================
Handler for wikified plain text content
*/
class PlainWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return this.fakeNode.textContent;
}
}
/*
==========================================
HTML Encoded Plain Wikified View Handler
==========================================
Handler for HTML-encoded wikified plain text
*/
class HTMLEncodedPlainWikifiedViewHandler extends WikifiedViewHandler {
getValue() {
return $tw.utils.htmlEncode(this.fakeNode.textContent);
}
}
/*
==========================================
HTML Encoded View Handler
==========================================
Handler for HTML-encoded text
*/
class HTMLEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.htmlEncode(this.widget.getValueAsText());
}
}
/*
==========================================
HTML Text Encoded View Handler
==========================================
Handler for HTML text-encoded content
*/
class HTMLTextEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.htmlTextEncode(this.widget.getValueAsText());
}
}
/*
==========================================
URL Encoded View Handler
==========================================
Handler for URL-encoded text
*/
class URLEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.encodeURIComponentExtended(this.widget.getValueAsText());
}
}
/*
==========================================
Double URL Encoded View Handler
==========================================
Handler for double URL-encoded text
*/
class DoubleURLEncodedViewHandler extends ViewHandler {
getValue() {
const text = this.widget.getValueAsText();
return $tw.utils.encodeURIComponentExtended($tw.utils.encodeURIComponentExtended(text));
}
}
/*
==========================================
Date View Handler
==========================================
Handler for date formatting
*/
class DateViewHandler extends ViewHandler {
getValue() {
const format = this.viewTemplate || "YYYY MM DD 0hh:0mm";
const rawValue = this.widget.getValueAsText();
const value = $tw.utils.parseDate(rawValue);
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.formatDateString(value, format);
} else {
return "";
}
}
}
/*
==========================================
Relative Date View Handler
==========================================
Handler for relative date display
*/
class RelativeDateViewHandler extends ViewHandler {
getValue() {
const rawValue = this.widget.getValueAsText();
const value = $tw.utils.parseDate(rawValue);
if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
return $tw.utils.getRelativeDate((new Date()) - (new Date(value))).description;
} else {
return "";
}
}
}
/*
==========================================
Strip Comments View Handler
==========================================
Handler for stripping comments from text
*/
class StripCommentsViewHandler extends ViewHandler {
getValue() {
const lines = this.widget.getValueAsText().split("\n");
const out = [];
for(const text of lines) {
if(!/^\s*\/\/#/.test(text)) {
out.push(text);
}
}
return out.join("\n");
}
}
/*
==========================================
JS Encoded View Handler
==========================================
Handler for JavaScript string encoding
*/
class JSEncodedViewHandler extends ViewHandler {
getValue() {
return $tw.utils.stringify(this.widget.getValueAsText());
}
}
/*
==========================================
ViewHandlerFactory
==========================================
Factory for creating appropriate view handlers based on format
*/
const ViewHandlerFactory = {
handlers: {
"text": TextViewHandler,
"htmlwikified": HTMLWikifiedViewHandler,
"plainwikified": PlainWikifiedViewHandler,
"htmlencodedplainwikified": HTMLEncodedPlainWikifiedViewHandler,
"htmlencoded": HTMLEncodedViewHandler,
"htmltextencoded": HTMLTextEncodedViewHandler,
"urlencoded": URLEncodedViewHandler,
"doubleurlencoded": DoubleURLEncodedViewHandler,
"date": DateViewHandler,
"relativedate": RelativeDateViewHandler,
"stripcomments": StripCommentsViewHandler,
"jsencoded": JSEncodedViewHandler
},
createHandler(format, widget) {
const HandlerClass = this.handlers[format] || this.handlers["text"];
return new HandlerClass(widget);
},
registerHandler(format, handlerClass) {
this.handlers[format] = handlerClass;
}
}; };
exports.view = ViewWidget; /*
==========================================
ViewWidget
==========================================
Main widget class that orchestrates view handlers
*/
class ViewWidget extends Widget {
constructor(parseTreeNode, options) {
super();
this.initialise(parseTreeNode, options);
}
render(parent, nextSibling) {
this.parentDomNode = parent;
this.computeAttributes();
this.execute();
this.viewHandler = ViewHandlerFactory.createHandler(this.viewFormat, this);
this.viewHandler.render(parent, nextSibling);
}
execute() {
this.viewTitle = this.getAttribute("tiddler", this.getVariable("currentTiddler"));
this.viewSubtiddler = this.getAttribute("subtiddler");
this.viewField = this.getAttribute("field", "text");
this.viewIndex = this.getAttribute("index");
this.viewFormat = this.getAttribute("format", "text");
this.viewTemplate = this.getAttribute("template", "");
this.viewMode = this.getAttribute("mode", "block");
}
getValue(options = {}) {
let value = options.asString ? "" : undefined;
if(this.viewIndex) {
value = this.wiki.extractTiddlerDataItem(this.viewTitle, this.viewIndex);
} else {
let tiddler;
if(this.viewSubtiddler) {
tiddler = this.wiki.getSubTiddler(this.viewTitle, this.viewSubtiddler);
} else {
tiddler = this.wiki.getTiddler(this.viewTitle);
}
if(tiddler) {
if(this.viewField === "text" && !this.viewSubtiddler) {
value = this.wiki.getTiddlerText(this.viewTitle);
} else {
if($tw.utils.hop(tiddler.fields, this.viewField)) {
if(options.asString) {
value = tiddler.getFieldString(this.viewField);
} else {
value = tiddler.fields[this.viewField];
}
}
}
} else {
if(this.viewField === "title") {
value = this.viewTitle;
}
}
}
return value;
}
getValueAsText() {
return this.getValue({asString: true});
}
refresh(changedTiddlers) {
const changedAttributes = this.computeAttributes();
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index ||
changedAttributes.template || changedAttributes.format || changedTiddlers[this.viewTitle]) {
this.refreshSelf();
return true;
} else {
return this.viewHandler.refresh(changedTiddlers);
}
}
}
exports.view = ViewWidget;

View File

@@ -369,16 +369,31 @@ Sort an array of tiddler titles by a specified field
isDescending: true if the sort should be descending isDescending: true if the sort should be descending
isCaseSensitive: true if the sort should consider upper and lower case letters to be different isCaseSensitive: true if the sort should consider upper and lower case letters to be different
*/ */
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric,locale) { exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
var self = this; var self = this;
if(sortField === "title") { if(sortField === "title") {
if(!isNumeric && !isAlphaNumeric) { if(!isNumeric && !isAlphaNumeric) {
const sorter = new Intl.Collator(locale, { sensitivity: isCaseSensitive ? "variant" : "accent" }); if(isCaseSensitive) {
if(isDescending) { if(isDescending) {
titles.sort((a,b) => sorter.compare(b, a)); titles.sort(function(a,b) {
return b.localeCompare(a);
});
} else {
titles.sort(function(a,b) {
return a.localeCompare(b);
});
}
} else { } else {
titles.sort((a,b) => sorter.compare(a, b)); if(isDescending) {
} titles.sort(function(a,b) {
return b.toLowerCase().localeCompare(a.toLowerCase());
});
} else {
titles.sort(function(a,b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
}
}
} else { } else {
titles.sort(function(a,b) { titles.sort(function(a,b) {
var x,y; var x,y;
@@ -399,8 +414,14 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
} }
} }
} }
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" }); if(isAlphaNumeric) {
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b); return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
}); });
} }
} else { } else {
@@ -442,8 +463,14 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
} }
a = String(a); a = String(a);
b = String(b); b = String(b);
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" }); if(isAlphaNumeric) {
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b); return isDescending ? b.localeCompare(a,undefined,{numeric: true,sensitivity: "base"}) : a.localeCompare(b,undefined,{numeric: true,sensitivity: "base"});
}
if(!isCaseSensitive) {
a = a.toLowerCase();
b = b.toLowerCase();
}
return isDescending ? b.localeCompare(a) : a.localeCompare(b);
}); });
} }
}; };

View File

@@ -25,6 +25,7 @@ title: $:/core/templates/tiddlywiki5.html
`{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/core/wiki/rawmarkup]] ||$:/core/templates/plain-text-tiddler}}} `{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/core/wiki/rawmarkup]] ||$:/core/templates/plain-text-tiddler}}}
{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkup]] ||$:/core/templates/plain-text-tiddler}}} {{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkup]] ||$:/core/templates/plain-text-tiddler}}}
{{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkupWikified]] ||$:/core/templates/raw-static-tiddler}}}` {{{ [enlist<saveTiddlerAndShadowsFilter>tag[$:/tags/RawMarkupWikified]] ||$:/core/templates/raw-static-tiddler}}}`
<!--~~ Style section start ~~-->
</head> </head>
<body class="tc-body"> <body class="tc-body">
<!--~~ Raw markup for the top of the body section ~~--> <!--~~ Raw markup for the top of the body section ~~-->

View File

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

View File

@@ -0,0 +1,15 @@
title: $:/core/ui/RootStylesheet
code-body: yes
\import [subfilter{$:/core/config/GlobalImportFilter}]
\whitespace trim
<$let currentTiddler={{$:/language}} languageTitle={{!!name}}>
<style type="text/css">
<$view tiddler="$:/themes/tiddlywiki/vanilla/reset" format="text" mode="block"/>
</style>
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Stylesheet]!is[draft]] -[[$:/themes/tiddlywiki/vanilla/reset]]">
<style type="text/css">
<$view format={{{ [<currentTiddler>tag[$:/tags/Stylesheet/Static]then[text]else[plainwikified]] }}} mode="block"/>
</style>
</$list>
</$let>

View File

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

View File

@@ -2,7 +2,7 @@ title: $:/core/ui/TiddlerInfo
\whitespace trim \whitespace trim
<div style="position:relative;"> <div style="position:relative;">
<div class="tc-tiddler-controls tc-tiddler-info-controls"> <div class="tc-tiddler-controls" style="position:absolute;right:0;">
<$reveal state="$:/config/TiddlerInfo/Mode" type="match" text="sticky"> <$reveal state="$:/config/TiddlerInfo/Mode" type="match" text="sticky">
<$button set=<<tiddlerInfoState>> setTo="" tooltip={{$:/language/Buttons/Info/Hint}} aria-label={{$:/language/Buttons/Info/Caption}} class="tc-btn-invisible"> <$button set=<<tiddlerInfoState>> setTo="" tooltip={{$:/language/Buttons/Info/Hint}} aria-label={{$:/language/Buttons/Info/Caption}} class="tc-btn-invisible">
{{$:/core/images/close-button}} {{$:/core/images/close-button}}

View File

@@ -11,13 +11,9 @@ tags: $:/tags/ViewTemplate
storyview="pop" storyview="pop"
variable="listItem" variable="listItem"
> >
<$let condition={{{ [<listItem>get[condition]] }}}> <$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]">
<%if [<condition>!is[blank]] :and[<currentTiddler>subfilter<condition>limit[1]] :else[<condition>is[blank]then[true]] %> <$transclude tiddler=<<listItem>>/>
<$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]"> </$set>
<$transclude tiddler=<<listItem>>/>
</$set>
<%endif%>
</$let>
</$list> </$list>
</span> </span>
<$set name="tv-wikilinks" value={{$:/config/Tiddlers/TitleLinks}}> <$set name="tv-wikilinks" value={{$:/config/Tiddlers/TitleLinks}}>

View File

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

View File

@@ -1,39 +0,0 @@
title: $:/core/macros/CSS/property
<!-- CSS property macros -->
<!-- TODO: Deprecate the following CSS macros once 2020 baseline is supported -->
\procedure margin-start(size)
-webkit-margin-start: <<size>>;
margin-inline-start: <<size>>;
\end
\procedure margin-end(size)
-webkit-margin-end: <<size>>;
margin-inline-end: <<size>>;
\end
\procedure padding-start(size)
-webkit-padding-start: <<size>>;
padding-inline-start: <<size>>;
\end
\procedure padding-end(size)
-webkit-padding-end: <<size>>;
padding-inline-end: <<size>>;
\end
\procedure margin-inline(start,end)
-webkit-margin-start: <<start>>;
margin-inline-start: <<start>>;
-webkit-margin-end: <<end>>;
margin-inline-end: <<end>>;
\end
\procedure padding-inline(start,end)
-webkit-padding-start: <<start>>;
padding-inline-start: <<start>>;
-webkit-padding-end: <<end>>;
padding-inline-end: <<end>>;
\end

View File

@@ -22,7 +22,7 @@ tags: $:/tags/Macro
<$action-listops $tiddler=<<targetTiddler>> $field=<<targetField>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/> <$action-listops $tiddler=<<targetTiddler>> $field=<<targetField>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/>
\end \end
\define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate, displayField:"caption") \define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate)
\whitespace trim \whitespace trim
<$set name="_tiddler" value="""$tiddler$""" emptyValue=<<currentTiddler>> > <$set name="_tiddler" value="""$tiddler$""" emptyValue=<<currentTiddler>> >
<$let field-reference={{{ [<_tiddler>] "!!" [[$field$]] +[join[]] }}} <$let field-reference={{{ [<_tiddler>] "!!" [[$field$]] +[join[]] }}}
@@ -42,7 +42,7 @@ tags: $:/tags/Macro
<$transclude tiddler="""$itemTemplate$"""> <$transclude tiddler="""$itemTemplate$""">
<$link to={{!!title}}> <$link to={{!!title}}>
<$let tv-wikilinks="no"> <$let tv-wikilinks="no">
<$transclude field=<<__displayField__>>> <$transclude field="caption">
<$view field="title"/> <$view field="title"/>
</$transclude> </$transclude>
</$let> </$let>
@@ -92,7 +92,7 @@ tags: $:/tags/Macro
</$set> </$set>
\end \end
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"",displayField:"title") \define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"")
\whitespace trim \whitespace trim
<span class="tc-tagged-draggable-list"> <span class="tc-tagged-draggable-list">
<$set name="tag" value=<<__tag__>>> <$set name="tag" value=<<__tag__>>>
@@ -110,11 +110,7 @@ tags: $:/tags/Macro
<$genesis $type=<<__elementTag__>>> <$genesis $type=<<__elementTag__>>>
<$transclude tiddler="""$itemTemplate$"""> <$transclude tiddler="""$itemTemplate$""">
<$link to={{!!title}}> <$link to={{!!title}}>
<$let tv-wikilinks="no"> <$view field="title"/>
<$transclude field=<<__displayField__>>>
<$view field="title"/>
</$transclude>
</$let>
</$link> </$link>
</$transclude> </$transclude>
</$genesis> </$genesis>

View File

@@ -9,9 +9,8 @@ code-body: yes
setTo=<<currentTab>> setTo=<<currentTab>>
default=<<__default__>> default=<<__default__>>
selectedClass="tc-tab-selected" selectedClass="tc-tab-selected"
selectedAria="aria-selected"
tooltip={{!!tooltip}} tooltip={{!!tooltip}}
role="tab" role="switch"
data-tab-title=<<currentTab>> data-tab-title=<<currentTab>>
> >
<$tiddler tiddler=<<save-currentTiddler>>> <$tiddler tiddler=<<save-currentTiddler>>>
@@ -58,12 +57,12 @@ code-body: yes
\whitespace trim \whitespace trim
<$qualify title=<<__state__>> name="qualifiedState"> <$qualify title=<<__state__>> name="qualifiedState">
<$let tabsState={{{ [<__explicitState__>minlength[1]] ~[<qualifiedState>] }}}> <$let tabsState={{{ [<__explicitState__>minlength[1]] ~[<qualifiedState>] }}}>
<div class={{{ [[tc-tab-set]addsuffix[ ]addsuffix<__class__>] }}} role="tablist"> <div class={{{ [[tc-tab-set]addsuffix[ ]addsuffix<__class__>] }}}>
<div class={{{ [[tc-tab-buttons]addsuffix[ ]addsuffix<__class__>] }}}> <div class={{{ [[tc-tab-buttons]addsuffix[ ]addsuffix<__class__>] }}}>
<<tabs-tab-list>> <<tabs-tab-list>>
</div> </div>
<div class={{{ [[tc-tab-divider]addsuffix[ ]addsuffix<__class__>] }}}/> <div class={{{ [[tc-tab-divider]addsuffix[ ]addsuffix<__class__>] }}}/>
<div class={{{ [[tc-tab-content]addsuffix[ ]addsuffix<__class__>] }}} role="tabpanel"> <div class={{{ [[tc-tab-content]addsuffix[ ]addsuffix<__class__>] }}}>
<<tabs-tab-body>> <<tabs-tab-body>>
</div> </div>
</div> </div>

View File

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

View File

@@ -0,0 +1,17 @@
caption: savetiddlers
color: #4DB6AC
community-author: Buggyj
created: 20171109171935039
delivery: Browser Extension
description: Extension pour les navigateurs Chrome et Firefox
fr-title:
method: save
modified: 20220402105820520
tags: Chrome Firefox Saving [[Other Resources]] plugins
title: "savetiddlers" Extension for Chrome and Firefox by buggyj
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
Une extension pour Google Chrome et Mozilla Firefox qui fluidifie l'utilisation de [[l'enregistreur HTML5 par défaut|Saving with the HTML5 fallback saver]] de <<tw>>, et le rend presque aussi convivial que ~TiddlyFox une fois configurée.
https://github.com/buggyj/savetiddlers

View File

@@ -1,17 +0,0 @@
caption: savetiddlers
color: #4DB6AC
community-author: buggyj
created: 20171109171935039
delivery: Browser Extension
description: Extension pour les navigateur Firefox
fr-title:
method: save
modified: 20250809092435788
tags: Firefox Saving [[Other Resources]] plugins
title: savetiddlers: Extension for Firefox by buggyj
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
Une extension Mozilla Firefox qui fluidifie l'utilisation de [[l'enregistreur HTML5 par défaut|Saving with the HTML5 fallback saver]] de <<tw>>, et le rend presque aussi convivial que [[TiddlyFox]] une fois configurée.
{{!!url}}

View File

@@ -0,0 +1,18 @@
caption: savetiddlers
color: #4DB6AC
community-author: Buggyj
created: 20171109171935039
delivery: Browser Extension
description: ChromeとFirefoxのブラウザ拡張機能
method: save
modified: 20241014110546647
original-modified: 20210106151027189
tags: Chrome Firefox Saving [[Other Resources]] plugins
title: "savetiddlers" Extension for Chrome and Firefox by buggyj
ja-title: buggyjによるChromeとFirefoxの"savetiddlers"拡張機能
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
Google ChromeとMozilla Firefoxの拡張機能で、TiddlyWikiの組み込み[[HTML5セーバー|Saving with the HTML5 saver]]による使いにくさの一部を解消し、正しく設定すればTiddlyFoxとほぼ同じくらい簡単に使用できるようになります。
https://github.com/buggyj/savetiddlers

View File

@@ -1,18 +0,0 @@
caption: savetiddlers
color: #4DB6AC
community-author: buggyj
created: 20171109171935039
delivery: Browser Extension
description: Firefoxのブラウザ拡張機能
method: save
modified: 20250809092435788
original-modified: 20250809092435788
tags: Firefox Saving [[Other Resources]] plugins
title: savetiddlers: Extension for Firefox by buggyj
ja-title: buggyjによるFirefoxの"savetiddlers"拡張機能
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
Mozilla Firefoxの拡張機能で、TiddlyWikiの組み込み[[HTML5セーバー|Saving with the HTML5 saver]]による使いにくさの一部を解消し、正しく設定すれば[[TiddlyFox]]とほぼ同じくらい簡単に使用できるようになります。
{{!!url}}

View File

@@ -1,18 +0,0 @@
title: ElementMapping/Basic
description: Mapping one element to another
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<!-- Map <p> to <div>, adding the class my-class -->
\define tv-map-p() div
This is a paragraph
+
title: ExpectedResult
<div data-element-mapping-from="p">This is a paragraph</div>

View File

@@ -1,19 +0,0 @@
title: ElementMapping/BasicWithClass
description: Mapping one element to another with an added class
type: text/vnd.tiddlywiki-multiple
tags: [[$:/tags/wiki-test-spec]]
title: Output
\whitespace trim
<!-- Map <p> to <div>, adding the class my-class -->
\define tv-map-p() div
\define tv-map-p-class() my-class
This is a paragraph
+
title: ExpectedResult
<div class="my-class" data-element-mapping-from="p">This is a paragraph</div>

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-a
type: text/html type: text/html
description: Horizontal tabs test - This is the expected HTML output from a test in test-wikitext-tabs-macro.js description: Horizontal tabs test - This is the expected HTML output from a test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set " role="tablist"><div class="tc-tab-buttons "><button aria-selected="false" class="" data-tab-title="TabOne" role="tab">t 1</button><button aria-selected="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="tab">t 2</button><button aria-selected="false" class="" data-tab-title="TabThree" role="tab">t 3</button><button aria-selected="false" class="" data-tab-title="TabFour" role="tab">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content " role="tabpanel"><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p> <p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-all
type: text/html type: text/html
description: Horizontal tabs with all parameters active. This is the expected HTML output from a test in test-wikitext-tabs-macro.js description: Horizontal tabs with all parameters active. This is the expected HTML output from a test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set " role="tablist"><div class="tc-tab-buttons "><button aria-selected="false" class="" data-tab-title="TabOne" role="tab">t 1</button><button aria-selected="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="tab">t 2</button><button aria-selected="false" class="" data-tab-title="TabThree" role="tab">desc</button><button aria-selected="false" class="" data-tab-title="TabFour" role="tab">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content " role="tabpanel"><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><h2 class="">TabTwo</h2><p><p>Text tab 2</p></p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p> <p><div class="tc-tab-set "><div class="tc-tab-buttons "><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">desc</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider "></div><div class="tc-tab-content "><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><h2 class="">TabTwo</h2><p><p>Text tab 2</p></p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -2,4 +2,4 @@ title: expected-test-tabs-vertical
type: text/html type: text/html
description: Vertical tabs test -- This is the expected HTML output from the test in test-wikitext-tabs-macro.js description: Vertical tabs test -- This is the expected HTML output from the test in test-wikitext-tabs-macro.js
<p><div class="tc-tab-set tc-vertical" role="tablist"><div class="tc-tab-buttons tc-vertical"><button aria-selected="false" class="" data-tab-title="TabOne" role="tab">t 1</button><button aria-selected="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="tab">t 2</button><button aria-selected="false" class="" data-tab-title="TabThree" role="tab">t 3</button><button aria-selected="false" class="" data-tab-title="TabFour" role="tab">TabFour</button></div><div class="tc-tab-divider tc-vertical"></div><div class="tc-tab-content tc-vertical" role="tabpanel"><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p> <p><div class="tc-tab-set tc-vertical"><div class="tc-tab-buttons tc-vertical"><button class="" data-tab-title="TabOne" role="switch">t 1</button><button aria-checked="true" class=" tc-tab-selected" data-tab-title="TabTwo" role="switch">t 2</button><button class="" data-tab-title="TabThree" role="switch">t 3</button><button class="" data-tab-title="TabFour" role="switch">TabFour</button></div><div class="tc-tab-divider tc-vertical"></div><div class="tc-tab-content tc-vertical"><div class="tc-reveal" hidden="true"></div><div class="tc-reveal"><p>Text tab 2</p></div><div class="tc-reveal" hidden="true"></div><div class="tc-reveal" hidden="true"></div></div></div></p>

View File

@@ -1,6 +0,0 @@
created: 20251001034405510
list: A a Ä ä Z z O o Õ õ Ö ö Ü ü Y y
modified: 20251218023544134
tags:
title: Locale Example
type: text/vnd.tiddlywiki

View File

@@ -26,6 +26,7 @@ For the convenience of existing users, we also continue to operate the original
* [[TiddlyWiki Subreddit|https://www.reddit.com/r/TiddlyWiki5/]] * [[TiddlyWiki Subreddit|https://www.reddit.com/r/TiddlyWiki5/]]
* Chat on Discord at https://discord.gg/HFFZVQ8 * Chat on Discord at https://discord.gg/HFFZVQ8
* [[TiddlyWiki Subreddit|https://www.reddit.com/r/TiddlyWiki5/]]
!! Developers !! Developers

View File

@@ -0,0 +1,16 @@
caption: savetiddlers
color: #4DB6AC
community-author: Buggyj
created: 20171109171935039
delivery: Browser Extension
description: Browser extension for Chrome and Firefox
method: save
modified: 20210106151027189
tags: Chrome Firefox Saving [[Other Resources]] plugins
title: "savetiddlers" Extension for Chrome and Firefox by buggyj
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
An extension for Google Chrome and Mozilla Firefox that smoothes out some of the friction from TiddlyWiki's built-in [[HTML5 saver|Saving with the HTML5 saver]], making it almost as easy to use as TiddlyFox once it is set up correctly.
https://github.com/buggyj/savetiddlers

View File

@@ -1,16 +0,0 @@
caption: savetiddlers
color: #4DB6AC
community-author: buggyj
created: 20171109171935039
delivery: Browser Extension
description: Browser extension for Firefox
method: save
modified: 20250809092435788
tags: Firefox Saving [[Other Resources]] plugins
title: savetiddlers: Extension for Firefox by buggyj
type: text/vnd.tiddlywiki
url: https://github.com/buggyj/savetiddlers
An extension for Mozilla Firefox that smoothes out some of the friction from TiddlyWiki's built-in [[HTML5 saver|Saving with the HTML5 saver]], making it almost as easy to use as [[TiddlyFox]] once it is set up correctly.
{{!!url}}

View File

@@ -1,5 +1,5 @@
created: 20150117190213631 created: 20150117190213631
modified: 20251225215015507 modified: 20230226144641763
tags: Concepts tags: Concepts
title: Date Fields title: Date Fields
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
@@ -28,5 +28,4 @@ As an example, the <<.field created>> field of this tiddler has the value <<.val
Dates can be [[converted to other formats|DateFormat]] for display: Dates can be [[converted to other formats|DateFormat]] for display:
<$macrocall $name="wikitext-example-without-html" <$macrocall $name="wikitext-example-without-html"
src="""<$view field="created" format="date" template="DDD DDth MMM YYYY"/>"""/> src="""<$view field="created" format="date" template="DDD DDth MMM YYYY"/>""">

View File

@@ -25,4 +25,4 @@ A filter output can change as tiddlers are added and deleted in the wiki. ~Tiddl
* <$linkcatcher message="tm-navigate" actions=<<openAdvancedSearch>> >[[Advanced Search|$:/AdvancedSearch]]</$linkcatcher> -- has a <<.advancedsearch-tab Filter>> tab that makes it easy to experiment with filters. * <$linkcatcher message="tm-navigate" actions=<<openAdvancedSearch>> >[[Advanced Search|$:/AdvancedSearch]]</$linkcatcher> -- has a <<.advancedsearch-tab Filter>> tab that makes it easy to experiment with filters.
* [[Filtered Transclusions|Transclusion in WikiText]] -- if you want to use filter results in your text * [[Filtered Transclusions|Transclusion in WikiText]] -- if you want to use filter results in your text
* [[Filter Syntax History]] -- if you are curious why the filter syntax is the way it is * [[TiddlyWiki Syntax History]] -- if you are curious why the filter syntax is the way it is

View File

@@ -0,0 +1,9 @@
created: 20131211220000000
modified: 20131211224200000
tags: Definitions
title: TiddlyIE
type: text/vnd.tiddlywiki
TiddlyIE is an extension for Internet Explorer that allows standalone TiddlyWiki files to save their changes directly to the file system. TiddlyIE works with the desktop version of Internet Explorer.
See [[Saving with TiddlyIE]].

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
created: 20150124112340000 created: 20150124112340000
modified: 20251218023608468 modified: 20150124113250000
tags: [[sort Operator]] [[Operator Examples]] tags: [[sort Operator]] [[Operator Examples]]
title: sort Operator (Examples) title: sort Operator (Examples)
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
@@ -11,10 +11,3 @@ type: text/vnd.tiddlywiki
<<.operator-example 3 "one two Three four +[sort[]]">> <<.operator-example 3 "one two Three four +[sort[]]">>
<<.operator-example 4 "[prefix[Tiddl]sort[text]]">> <<.operator-example 4 "[prefix[Tiddl]sort[text]]">>
<<.operator-example 5 "[has[created]sort[created]limit[10]]" "the oldest 10 tiddlers in the wiki">> <<.operator-example 5 "[has[created]sort[created]limit[10]]" "the oldest 10 tiddlers in the wiki">>
! Using a custom locale
The following examples shows the differences when using the sort operator with default, Swedish and Estonian locale.
<<.operator-example 6 "[list[Locale Example]sort[]]">>
<<.operator-example 7 "[list[Locale Example]sort[],[sv]]">>
<<.operator-example 8 "[list[Locale Example]sort[],[et]]">>

View File

@@ -1,15 +1,15 @@
caption: nsort
created: 20140410103123179 created: 20140410103123179
modified: 20251227084602319 modified: 20150203190051000
op-input: a [[selection of titles|Title Selection]]
op-neg-output: the input, likewise sorted into descending order
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as numbers
op-parameter: accept same parameters as the [[sort Operator]]
op-parameter-name: F
op-purpose: sort the input by number field
tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]] tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]
title: nsort Operator title: nsort Operator
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
caption: nsort
op-purpose: sort the input by number field
op-input: a [[selection of titles|Title Selection]]
op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
op-parameter-name: F
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as numbers
op-neg-output: the input, likewise sorted into descending order
Non-numeric values are treated as having a higher value than any number, and the difference between capital and lowercase letters is ignored. Compare <<.olink nsortcs>>. Non-numeric values are treated as having a higher value than any number, and the difference between capital and lowercase letters is ignored. Compare <<.olink nsortcs>>.

View File

@@ -1,10 +1,10 @@
caption: nsortcs caption: nsortcs
created: 20140410103123179 created: 20140410103123179
modified: 20251227084615705 modified: 20150417125717078
op-input: a [[selection of titles|Title Selection]] op-input: a [[selection of titles|Title Selection]]
op-neg-output: the input, likewise sorted into descending order op-neg-output: the input, likewise sorted into descending order
op-output: the input, sorted into ascending order by field <<.place F>>, treating field values as numbers op-output: the input, sorted into ascending order by field <<.place F>>, treating field values as numbers
op-parameter: accept same parameters as the [[sort Operator]] op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
op-parameter-name: F op-parameter-name: F
op-purpose: sort the input titles by number field, treating upper and lower case as different op-purpose: sort the input titles by number field, treating upper and lower case as different
tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]] tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]

View File

@@ -1,22 +1,16 @@
caption: sort
created: 20140410103123179 created: 20140410103123179
modified: 20251227084644651 modified: 20150203191228000
op-input: a [[selection of titles|Title Selection]]
op-neg-output: the input, likewise sorted into descending order
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as text
op-parameter: the <<.op sort>> operator accepts 1 or 2 parameters, see below for details
op-parameter-name: F
op-purpose: sort the input by text field
tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]] tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]
title: sort Operator title: sort Operator
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
caption: sort
op-purpose: sort the input by text field
op-input: a [[selection of titles|Title Selection]]
op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
op-parameter-name: F
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as text
op-neg-output: the input, likewise sorted into descending order
The difference between capital and lowercase letters is ignored. Compare <<.olink sortcs>>. The difference between capital and lowercase letters is ignored. Compare <<.olink sortcs>>.
```
[sort[<field>],[<locale>]]
```
* ''field'' : the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
* ''locale'': (optional). A string with a [[BCP 47 language tag|https://developer.mozilla.org/en-US/docs/Glossary/BCP_47_language_tag]]
<<.operator-examples "sort">> <<.operator-examples "sort">>

View File

@@ -1,10 +1,10 @@
caption: sortan caption: sortan
created: 20180222071605739 created: 20180222071605739
modified: 20251227084439804 modified: 20180223012553446
op-input: a [[selection of titles|Title Selection]] op-input: a [[selection of titles|Title Selection]]
op-neg-output: the input, likewise sorted into descending order op-neg-output: the input, likewise sorted into descending order
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as alphanumerics op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as alphanumerics
op-parameter: accept same parameters as the [[sort Operator]] op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
op-parameter-name: F op-parameter-name: F
op-purpose: sort the input by text field considering them as alphanumerics op-purpose: sort the input by text field considering them as alphanumerics
tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]] tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]

View File

@@ -1,10 +1,10 @@
caption: sortcs caption: sortcs
created: 20140410103123179 created: 20140410103123179
modified: 20251227084416522 modified: 20150417125704503
op-input: a [[selection of titles|Title Selection]] op-input: a [[selection of titles|Title Selection]]
op-neg-output: the input, likewise sorted into descending order op-neg-output: the input, likewise sorted into descending order
op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as text op-output: the input, sorted into ascending order by field <<.field F>>, treating field values as text
op-parameter: accept same parameters as the [[sort Operator]] op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
op-parameter-name: F op-parameter-name: F
op-purpose: sort the input by text field, treating upper and lower case as different op-purpose: sort the input by text field, treating upper and lower case as different
tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]] tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]

View File

@@ -0,0 +1,10 @@
caption: Internet Explorer
created: 20140811172058274
modified: 20211114031651879
tags: GettingStarted $:/deprecated
title: GettingStarted - Internet Explorer
type: text/vnd.tiddlywiki
{{Saving with TiddlyIE}}
The [[Windows HTA Hack]] describes an alternative method of using TiddlyWiki with Internet Explorer.

View File

@@ -1,5 +1,5 @@
created: 20150414070451144 created: 20150414070451144
list: [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - Latest Version]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - Funding]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]] [[HelloThumbnail - TiddlyWikiLinks]] list: [[HelloThumbnail - Community Survey 2025]] [[HelloThumbnail - Twenty Years of TiddlyWiki]] [[HelloThumbnail - Introduction Video]] [[HelloThumbnail - TiddlyWiki Privacy]] [[HelloThumbnail - Latest Version]] [[HelloThumbnail - Newsletter]] [[HelloThumbnail - Grok TiddlyWiki]] [[HelloThumbnail - TiddlyWikiLinks]] [[HelloThumbnail - MultiWikiServer]] [[HelloThumbnail - Funding]] [[HelloThumbnail - Marketplace]] [[HelloThumbnail - Intertwingled Innovations]]
modified: 20150414070948246 modified: 20150414070948246
title: HelloThumbnail title: HelloThumbnail
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki

View File

@@ -5,6 +5,5 @@ link: TiddlyWiki Newsletter
image: TiddlyWiki Newsletter Badge image: TiddlyWiki Newsletter Badge
color: #fff color: #fff
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
ribbon-text: NEW
Subscribe to the ~TiddlyWiki Newsletter, a summary of the most interesting and relevant news from the ~TiddlyWiki community Subscribe to the ~TiddlyWiki Newsletter, a summary of the most interesting and relevant news from the ~TiddlyWiki community

View File

@@ -0,0 +1,17 @@
caption: HTA Hack
color: #F06292
created: 20131212223146250
delivery: DIY
description: Manual method to let Internet Explorer save changes directly
method: save
modified: 20200507110355115
tags: Saving Windows $:/deprecated
title: Windows HTA Hack
type: text/vnd.tiddlywiki
<<.deprecated-since "5.3.6">>
Under Windows it is possible to convert TiddlyWiki into a true local application by renaming the HTML file to have the extension `*.hta`. The ''fsosaver'' module can then use the ~ActiveX ~FileSystemObject to save changes.
Note that one disadvantage of this approach is that the TiddlyWiki file is saved in UTF-16 format, making it up to twice as large as it would be with the usual UTF-8 encoding. However, opening and saving the file via another saving method will re-encode the file to UTF-8.
See Wikipedia for more details: https://en.wikipedia.org/wiki/HTML_Application

View File

@@ -31,10 +31,6 @@ The <<.def list-links-draggable>> [[macro|Macros]] renders the ListField of a ti
; itemTemplate ; itemTemplate
: Optional title of a tiddler to use as the template for rendering list items : Optional title of a tiddler to use as the template for rendering list items
;displayField
: Optional name of the field to display when the list is rendered. Defaults to the "caption" field; if "caption" is not present, the "title" field is used instead
If the `itemTemplate` parameter is not provided then the list items are rendered as simple links. Within the `itemTemplate`, the [[currentTiddler Variable]] refers to the current list item. If the `itemTemplate` parameter is not provided then the list items are rendered as simple links. Within the `itemTemplate`, the [[currentTiddler Variable]] refers to the current list item.
<<.macro-examples "list-links-draggable">> <<.macro-examples "list-links-draggable">>

View File

@@ -17,9 +17,6 @@ The <<.def list-tagged-draggable>> [[macro|Macros]] renders the tiddlers with a
: Optional title of a tiddler to use as the template for rendering list items : Optional title of a tiddler to use as the template for rendering list items
;emptyMessage ;emptyMessage
: Optional wikitext to display if there are no tiddlers with the specified tag : Optional wikitext to display if there are no tiddlers with the specified tag
Heres a corrected and polished version of your sentence in clear, standard English:
;displayField
: Optional name of the field to display when the list is rendered. Defaults to `title` field.
Note that the [[ordering|Order of Tagged Tiddlers]] is accomplished by assigning a new list to the `list` field of the tag tiddler. Any `list-before` or `list-after` fields on any of the other tiddlers carrying the tag are also removed to ensure the `list` field is respected. Note that the [[ordering|Order of Tagged Tiddlers]] is accomplished by assigning a new list to the `list` field of the tag tiddler. Any `list-before` or `list-after` fields on any of the other tiddlers carrying the tag are also removed to ensure the `list` field is respected.

View File

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

View File

@@ -0,0 +1,17 @@
title: $:/changenotes/5.4.0/#8130
created: 20251212171804335
modified: 20251212171804335
tags: $:/tags/ChangeNote
change-type: performance
change-category: internal
description: Different Stylesheets are now included as single `<style>` tags in the Header
release: 5.4.0
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/8130
github-contributors: BurningTreeC
type: text/vnd.tiddlywiki
Previously, all stylesheets were combined in a single `<style>` tag in the `<head>`.
Now, a separate `<style>` tag is created in the `<head>` for each stylesheet.
As part of these changes, the 'view widget' has also been updated. It can now respond dynamically to changes in the 'wikified' formats as well.

View File

@@ -1,10 +0,0 @@
title: $:/changenotes/5.4.0/#9148
description: Bidirectional improvements for core classes
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: theme
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9148
github-contributors: Leilei332
Make some core classes display properly when Tiddlywiki's language uses bidrectional scripts.

View File

@@ -1,12 +0,0 @@
title: $:/changenotes/5.4.0/#9177
description: Add Display Field to list-tagged-draggable and list-links-draggable
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: usability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9177
github-contributors: kookma
A new input parameter, `displayField`, has been added to the `list-links-draggable` and `list-tagged-draggable` macros,
allowing users to specify which field (e.g., title, caption, or any custom field) should be displayed when a tiddler is
rendered via the draggable macro.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
title: $:/changenotes/5.4.0/#9348
description: Improve tabs macro accessibility
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: usability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9348
github-contributors: Leilei332
Adds `tablist`, `tabpanel` and `tab` roles to the tabs macro to improve its accessibility. It also adds a `selectedAria` attribute to the button widget.

View File

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

View File

@@ -1,9 +0,0 @@
title: $:/changenotes/5.4.0/#9400/impacts/collator
changenote: $:/changenotes/5.4.0/#9400
created: 20251114102355243
modified: 20251114102355243
tags: $:/tags/ImpactNote
description: Tiddlywiki no longer works on browsers that doesn't support [[Intl.Collator|https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator]]
impact-type: compatibility-break

View File

@@ -1,10 +0,0 @@
title: $:/changenotes/5.4.0/#9400
description: Add locale support for sort operators
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: feature
change-category: filters
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9400
github-contributors: Leilei332
Add a new parameter for `sort`, `nsort`, `sortan`, `sortcs` and `nsortcs` to support sorting with a custom locale.

View File

@@ -1,15 +0,0 @@
title: $:/changenotes/5.4.0/#9466
description: ViewToolbar buttons now support condition field
tags: $:/tags/ChangeNote
release: 5.4.0
change-type: feature
change-category: hackability
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9466
github-contributors: linonetwo
ViewToolbar buttons can now be conditionally displayed based on the currentTiddler using a `condition` field. Similar to how `$:/tags/Exporter` and `$:/tags/EditorTools` already have. An example would be:
```tid
tags: $:/tags/ViewToolbar
condition: [<currentTiddler>type[text/x-markdown]] [<currentTiddler>type[text/markdown]]
```

View File

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

View File

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

View File

@@ -1,10 +0,0 @@
title: $:/changenotes/5.4.0/#9570
description: Fix images loaded from _canonical_uri tiddlers not having progress classes assigned
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: bugfix
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9570
github-contributors: jermolene
Fixes issue whereby transcluding a _canonical_uri tiddler with a missing image did not assign the progress classes `tc-image-loading`, `tc-image-loaded` and `tc-image-error`.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,11 +0,0 @@
title: $:/changenotes/5.4.0/#9511/impacts/api
changenote: $:/changenotes/5.4.0/#9511
created: 20251220010540143
modified: 20251220010540143
tags: $:/tags/ImpactNote
description: The diff-match-patch-es library uses different APIs
impact-type: compatibility-break
* Default export and the class constructor has been removed
* Function name has been unified to camelCase
* Previous options like Diff_Timeout and Diff_EditCost are now passed as an options object in the arguments if needed

View File

@@ -1,10 +0,0 @@
title: $:/changenotes/5.4.0/#9511
description: Migrate diff-match-patch library to diff-match-patch-es
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: developer
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9511
github-contributors: Leilei332
Migrate the unmaintained [[diff-match-patch|https://github.com/google/diff-match-patch]] library to the maintained and modern fork [[diff-match-patch-es|https://github.com/antfu/diff-match-patch-es]].

View File

@@ -1,14 +0,0 @@
title: $:/changenotes/5.4.0/#9488
description: Refactor base64 utility functions
release: 5.4.0
tags: $:/tags/ChangeNote
change-type: enhancement
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9488
github-contributors: Leilei332
Refactor base64 utility functions in [[$:/core/modules/utils/utils.js]] to make it easier for maintainence.
* Split base64 utility functions to two platforms
* Use `TextEncoder` and `TextDecoder` api in Node.js
* Do not export `base64ToBytes` and `bytesToBase64`

View File

@@ -4,7 +4,7 @@ created: 20160216191710789
delivery: Protocol delivery: Protocol
description: Standard web protocol available on products such as Sharepoint description: Standard web protocol available on products such as Sharepoint
method: save method: save
modified: 20260102081028704 modified: 20220615155048712
tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP Safari Saving Windows iOS Edge tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP Safari Saving Windows iOS Edge
title: Saving via WebDAV title: Saving via WebDAV
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
@@ -19,9 +19,6 @@ Lightweight, portable and easy to use solutions
* [[rclone|https://rclone.org/commands/rclone_serve_webdav/]] * [[rclone|https://rclone.org/commands/rclone_serve_webdav/]]
** Running it can be as simple as: <br/>`rclone serve webdav some_directory_containing_tiddlywiki_files` ** Running it can be as simple as: <br/>`rclone serve webdav some_directory_containing_tiddlywiki_files`
* [[copyparty|https://github.com/9001/copyparty]]
** Copyparty comes with a ~WebDAV server. Simply run `copyparty -v .::rwd:c,daw` to serve the current folder and visit [[http://[::1]:3923/]] to use TiddlyWiki
** Note that you need to grant read, write and delete permission and add `daw` volflag to allow copyparty to overwrite existing files.
* [[micromata dave - the simple webdav server|https://github.com/micromata/dave]] * [[micromata dave - the simple webdav server|https://github.com/micromata/dave]]
* [[dav-server|https://github.com/edrex/dav-server]] is a quick way to serve up a folder of HTML ~TiddlyWikis. * [[dav-server|https://github.com/edrex/dav-server]] is a quick way to serve up a folder of HTML ~TiddlyWikis.
* [[hacdias webdav server|https://github.com/hacdias/webdav/]] * [[hacdias webdav server|https://github.com/hacdias/webdav/]]
@@ -47,10 +44,6 @@ Lightweight, portable and easy to use solutions
* RCX is an open source file manager for Android based on //rclone//. It is available on both //F-Droid// and //Google Play//. Thanks to its integrated WebDAV server, it lets you edit the wikis that you keep in your pocket. You can share them with other devices on the local network too. * RCX is an open source file manager for Android based on //rclone//. It is available on both //F-Droid// and //Google Play//. Thanks to its integrated WebDAV server, it lets you edit the wikis that you keep in your pocket. You can share them with other devices on the local network too.
!! iOS
* There are no native apps that can serve a ~WebDAV server, but you can use rclone or copyparty on [[iSH Shell|https://apps.apple.com/cn/app/ish-shell/id1436902243]] or copyparty on [[a-Shell|https://apps.apple.com/cn/app/a-shell/id1473805438]].
!! Servers !! Servers
Many [[NAS|https://en.wikipedia.org/wiki/NAS]] or [[Subversion|https://en.wikipedia.org/wiki/Apache_Subversion]] servers support ~WebDAV out of the box. Setting up your own server might take some effort though: Many [[NAS|https://en.wikipedia.org/wiki/NAS]] or [[Subversion|https://en.wikipedia.org/wiki/Apache_Subversion]] servers support ~WebDAV out of the box. Setting up your own server might take some effort though:

View File

@@ -0,0 +1,25 @@
caption: ~TiddlyIE
color: #4DB6AC
community-author: David Jade
created: 20131211220000000
delivery: Browser Extension
description: Browser extension for Internet Explorer
method: save
modified: 20200507201415232
tags: [[Internet Explorer]] Saving $:/deprecated
title: Saving with TiddlyIE
type: text/vnd.tiddlywiki
<<.deprecated-since "5.3.6">>
# Install the TiddlyIE add-on from:
#* https://github.com/davidjade/TiddlyIE/releases
# Restart Internet Explorer. IE will prompt you to enable the TiddlyIE add-on.
#> You may also see a prompt to enable the //Microsoft Script Runtime//
# [[Download]] an empty TiddlyWiki by saving this link:
#> https://tiddlywiki.com/empty.html
# Locate the file you just downloaded
#* You may rename it, but be sure to keep the `.html` or `.htm` extension
# Open the file in Internet Explorer
# Try creating a new tiddler using the ''new tiddler'' <<.icon $:/core/images/new-button>> button in the sidebar. Type some content for the tiddler, and click the <<.icon $:/core/images/done-button>> ''ok'' button
# Save your changes by clicking the <<.icon $:/core/images/save-button-dynamic>> ''save changes'' button in the sidebar. Internet Explorer will ask for your consent to save the file locally by presenting a file ''Save As'' dialog.
# Refresh the browser window to verify that your changes have been saved correctly

View File

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

View File

@@ -1,77 +1,51 @@
caption: action-log caption: action-log
created: 20201114113318785 created: 20201114113318785
modified: 20260105121108063 modified: 20201120155202652
tags: Widgets ActionWidgets [[Debugging Widgets]] tags: Widgets ActionWidgets [[Debugging Widgets]]
title: ActionLogWidget title: ActionLogWidget
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
! Introduction ! Introduction
<<.from-version "5.1.23">> The <<.wid action-log>> widget is an [[action widget|ActionWidgets]] that can be used to output debugging information to the [[JavaScript console|Web Developer Tools]] supported by most browsers. This can be useful to observe and debug the behavior within a sequence of actions. <<.from-version "5.1.23">> The ''action-log'' widget is an [[action widget|ActionWidgets]] that can be used to output debugging information to the [[JavaScript console|Web Developer Tools]] supported by most browsers. This can be useful because otherwise it is difficult to observe what is going on within a sequence of actions.
When the action is invoked, the names and values of all [[attributes|Widget Attributes]] are logged to the JavaScript console.
```
<$action-log name=value />
```
ActionWidgets are used within triggering widgets such as the ButtonWidget. ActionWidgets are used within triggering widgets such as the ButtonWidget.
<<.note """ For debugging outside of actions see [[LogWidget]]""">> <<.tip """ For debugging outside of actions see [[LogWidget]]""">>
! Content and Attributes ! Content and Attributes
The <<.wid action-log>> widget is invisible. Any content within it is ignored. The ''action-log'' widget is invisible. Any content within it is ignored.
When the actions are invoked, the names and values of all attributes are logged to the JavaScript console.
In addition there are optional attributes that can be used:
|!Optional Attribute |!Description |
|$$filter|All variables matching this filter will also be logged. |
|$$message |A message to display as the title of the information logged. Useful when several `action-log` widgets are used in sequence. |
|$$all |Set to "yes" to log all variables in a collapsed table. Note that if there is nothing specified to log, all variables are always logged instead.|
<<.from-version "5.4.0">> Any [[multi-valued variables|Multi-Valued Variables]] or attributes are logged as a list of values. <<.from-version "5.4.0">> Any [[multi-valued variables|Multi-Valued Variables]] or attributes are logged as a list of values.
|!Attribute |!Description | <<.tip """A handy tip if an action widget is not behaving as expected is to temporarily change it to an `<$action-log>` widget so that the attributes can be observed.""">>
|<<.attr $$filter>>|(Optional) All variables whose name matches the [[Filter Expression]] will be logged |
|<<.attr $$message>> |(Optional) A message to display as the title of the information logged. Useful when several <<.wid action-log>> widgets are used in sequence |
|<<.attr $$all>> |(Optional) Set to <<.value yes>> to log all variables |
<<.note """ If `<$action-log />` is called without any attributes, all defined variables will be logged as if `$$all=yes` were set.""">> ! Example
<<.note """When logging [[Variable Attribute Values]], the body text of macros and procedures will be output as their value. Functions are evaluated and their first result is logged.""">> Here is an example of logging two variables:
! Examples
!! Basic Example
Log the value of variable <<.var name>>, the first result of the filter expression `[tag[Learning]]` and the value of field <<.field created>> of the current tiddler:
``` ```
<$action-log name=<<name>> filter={{{ [tag[Learning]] }}} created={{!!created}} /> <$action-log myVar=<<myVar>> otherVar=<<otherVar>>/>
``` ```
!! Example using <<.attr $$filter>> and <<.attr $$message>> To log all variables:
Log all core variables (which start with <<.var tv->>) with a table title:
``` ```
<$action-log $$message="Core Variables" $$filter="[prefix[tv-]]" /> <$action-log />
``` ```
!! Widget Debugging
Change a misbehaving <<.wlink ActionSetFieldWidget>> widget to an <<.wid action-log>> widget to verify that <<.var currentTiddler>> and <<.var value>> match their expected values: To log two variables as well as all core variables (which start with `tv-`):
<<.tip """If an action widget is not behaving as expected it is often useful to temporarily change it to an <<.wid action-log>> widget so that the passed attributes can be verified.""">>
``` ```
<$action-log $tiddler=<<currentTiddler>> $field="text" $value=<<value>> /> <$action-log myVar=<<myVar>> other={{!!status}} $$filter="[prefix[tv-]]"/>
``` ```
This application is the primary reason that the attributes of the <<.wid action-log>> widget are prefixed with two dollar signs instead of one. Otherwise, the attributes of the original widget could be interpreted as attributes to <<.wid action-log>> and lead to unintended consequences.
!! Example with Function
Log the <<.var tiddlerList>> function definition and its first evaluation result:
```
\function tiddlerList() [tag[Learning]]
<$action-log $$filter="[title[tiddlerList]]" value=<<tiddlerList>> />
```
<<.note """The values output with the <<.attr $$filter>> or <<.attr $$all>> attributes will only contain the definition of functions instead of their values, as the evaluation of many functions can lead to significant performance penalties.""">>

View File

@@ -1,6 +1,6 @@
caption: button caption: button
created: 20131024141900000 created: 20131024141900000
modified: 20251101091926820 modified: 20250720025737830
tags: Widgets TriggeringWidgets tags: Widgets TriggeringWidgets
title: ButtonWidget title: ButtonWidget
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
@@ -34,7 +34,6 @@ The content of the `<$button>` widget is displayed within the button.
|setIndex |An ''index'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present | |setIndex |An ''index'' to which the new value will be assigned, if the attribute <<.attr setTitle>> is present |
|setTo |The new value to assign to the TextReference identified in the `set` attribute or the text field / the field specified through <<.attr setField>> / the index specified through <<.attr setIndex>> of the title given through <<.attr setTitle>> | |setTo |The new value to assign to the TextReference identified in the `set` attribute or the text field / the field specified through <<.attr setField>> / the index specified through <<.attr setIndex>> of the title given through <<.attr setTitle>> |
|selectedClass |An optional additional CSS class to be assigned if the popup is triggered or the tiddler specified in <<.attr set>> already has the value specified in <<.attr setTo>> | |selectedClass |An optional additional CSS class to be assigned if the popup is triggered or the tiddler specified in <<.attr set>> already has the value specified in <<.attr setTo>> |
|selectedAria |<<.from-version "5.4.0">> An ARIA attribute to be set to `true` or `false` when <<.attr selectedClass>> is defined. Allowed values are `aria-checked` (default), `aria-selected` and `aria-pressed` |
|default |Default value if <<.attr set>> tiddler is missing for testing against <<.attr setTo>> to determine <<.attr selectedClass>> | |default |Default value if <<.attr set>> tiddler is missing for testing against <<.attr setTo>> to determine <<.attr selectedClass>> |
|popup |Title of a state tiddler for a popup that is toggled when the button is clicked. See PopupMechanism for details | |popup |Title of a state tiddler for a popup that is toggled when the button is clicked. See PopupMechanism for details |
|popupTitle |Title of a state tiddler for a popup that is toggled when the button is clicked. In difference to the <<.attr popup>> attribute, ''no'' TextReference is used. See PopupMechanism for details | |popupTitle |Title of a state tiddler for a popup that is toggled when the button is clicked. In difference to the <<.attr popup>> attribute, ''no'' TextReference is used. See PopupMechanism for details |

View File

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

View File

@@ -1,71 +1,45 @@
created: 20201120152706842 created: 20201120152706842
modified: 20260105121111637 modified: 20201120154927696
tags: Widgets [[Debugging Widgets]] tags: Widgets [[Debugging Widgets]]
title: LogWidget title: LogWidget
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
! Introduction ! Introduction
<<.from-version "5.1.23">> The <<.wid log>> widget is a [[widget|Widgets]] that can be used to output debugging information to the [[JavaScript console|Web Developer Tools]] supported by most browsers. <<.from-version "5.1.23">> The ''log'' widget can be used to output debugging information to the [[JavaScript console|Web Developer Tools]] supported by most browsers.
When the widget is rendered or refreshed, the names and values of all [[attributes|Widget Attributes]] are logged to the JavaScript console. <<.tip """ For use with ActionWidgets see [[ActionLogWidget]] which uses identical parameters""">>
```
<$log name=value />
```
<<.note """ For debugging inside of actions see [[ActionLogWidget]]""">>
! Content and Attributes ! Content and Attributes
The <<.wid log>> widget is invisible. Any content within it is ignored. The ''log'' widget is invisible. Any content within it is ignored. Note that the widget will log to the console both when it is first rendered and also every time it refreshes.
When the widget is rendered, the names and values of all attributes are logged to the JavaScript console.
In addition there are optional attributes that can be used:
|!Optional Attribute |!Description |
|$$filter|All variables matching this filter will also be logged. |
|$$message |A message to display as the title of the information logged. Useful when several `log` widgets are used in sequence. |
|$$all |Set to "yes" to log all variables in a collapsed table. Note that if there is nothing specified to log, all variables are always logged instead.|
|!Attribute |!Description | ! Example
|<<.attr $$filter>>|(Optional) All variables whose name matches the [[Filter Expression]] will be logged |
|<<.attr $$message>> |(Optional) A message to display as the title of the information logged. Useful when several <<.wid log>> widgets are used in sequence |
|<<.attr $$all>> |(Optional) Set to <<.value yes>> to log all variables |
<<.note """ If `<$log />` is called without any attributes, all defined variables will be logged as if `$$all=yes` were set.""">> Here is an example of logging two variables:
<<.note """When logging [[Variable Attribute Values]], the body text of macros and procedures will be output as their value. Functions are evaluated and their first result is logged.""">>
! Examples
!! Basic Example
Log the value of variable <<.var name>>, the first result of the filter expression `[tag[Learning]]` and the value of field <<.field created>> of the current tiddler:
``` ```
<$log name=<<name>> filter={{{ [tag[Learning]] }}} created={{!!created}} /> <$log myVar=<<myVar>> otherVar=<<otherVar>>/>
``` ```
!! Example using <<.attr $$filter>> and <<.attr $$message>> To log all variables:
Log all core variables (which start with <<.var tv->>) with a table title:
``` ```
<$log $$message="Core Variables" $$filter="[prefix[tv-]]" /> <$log />
``` ```
!! Widget Debugging
Change a misbehaving <<.wlink TranscludeWidget>> widget to a <<.wid log>> widget to verify that <<.var name>> and <<.var mode>> match their expected values: To log two variables as well as all core variables (which start with `tv-`):
<<.tip """If a widget is not behaving as expected it is often useful to temporarily change it to a <<.wid log>> widget so that the passed attributes can be verified.""">>
``` ```
<$log $variable=<<name>> $mode=<<mode>> /> <$log myVar=<<myVar>> other={{!!status}} $$filter="[prefix[tv-]]"/>
``` ```
This application is the primary reason that the attributes of the <<.wid log>> widget are prefixed with two dollar signs instead of one. Otherwise, the attributes of the original widget could be interpreted as attributes to <<.wid log>> and lead to unintended consequences.
!! Example with Function
Log the <<.var tiddlerList>> function definition and its first evaluation result (see browser console after clicking "Try it"):
<<.example n:"2" eg:"""\function tiddlerList() [tag[Learning]]
<$log $$filter="[title[tiddlerList]]" value=<<tiddlerList>> />""" >>
<<.note """The values output with the <<.attr $$filter>> or <<.attr $$all>> attributes will only contain the definition of functions instead of their values, as the evaluation of many functions can lead to significant performance penalties.""">>

View File

@@ -1,7 +1,14 @@
caption: Definitions
created: 20131205160424246 created: 20131205160424246
modified: 20251229110936191 modified: 20131205160450910
tags: WikiText
title: Definitions in WikiText title: Definitions in WikiText
type: text/vnd.tiddlywiki type: text/vnd.tiddlywiki
caption: Definitions
To use HTML Definition Lists through WikiText, see [[Description Lists in WikiText]]. HTML definition lists are created with this syntax:
<<wikitext-example src:"; Term being defined
: Definition of that term
; Another term
: Another definition
">>

View File

@@ -1,14 +0,0 @@
caption: Description Lists
created: 20131205160424246
modified: 20251229110936191
tags: WikiText
title: Description Lists in WikiText
type: text/vnd.tiddlywiki
HTML description lists (<abbr title="also known as">AKA</abbr> definition lists) are created with this syntax:
<<wikitext-example src:"; Term being described
: Description / Definition of that term
; Another term
: Another description / definition
">>

Some files were not shown because too many files have changed in this diff Show More