mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-02-14 14:09:51 +00:00
Compare commits
65 Commits
fix-browse
...
default-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82fc2f24b2 | ||
|
|
b6106ee4d9 | ||
|
|
d2faad2c58 | ||
|
|
f41ed1c88c | ||
|
|
73cd48cada | ||
|
|
3b84a7042c | ||
|
|
3f81e3651e | ||
|
|
c4d0b61827 | ||
|
|
adf9853ce4 | ||
|
|
5f03d1e6ac | ||
|
|
0ffb4d988b | ||
|
|
f2fbcf60a2 | ||
|
|
8276f66edf | ||
|
|
b6859c5a2d | ||
|
|
beb6839a35 | ||
|
|
f3e9beb1e1 | ||
|
|
2a1c607450 | ||
|
|
9b56734451 | ||
|
|
2f8d53d3f7 | ||
|
|
ae4e99951a | ||
|
|
be84dee26b | ||
|
|
00e17874f0 | ||
|
|
9041f099a3 | ||
|
|
3ba31be2a8 | ||
|
|
99d8afd515 | ||
|
|
2ab5f26644 | ||
|
|
419fe68ee2 | ||
|
|
0e765bdbdb | ||
|
|
855d8a9638 | ||
|
|
afcf108d29 | ||
|
|
8f9acc0ca2 | ||
|
|
5e4b8fbb3c | ||
|
|
8e301178a4 | ||
|
|
a72d3a09bf | ||
|
|
56634ffe29 | ||
|
|
24c317e1ab | ||
|
|
07329c6849 | ||
|
|
47ab3476f6 | ||
|
|
f0e64660f2 | ||
|
|
9663e65f4b | ||
|
|
7cb422242a | ||
|
|
f075f24e6b | ||
|
|
5fa1098c03 | ||
|
|
92dc927c7b | ||
|
|
98a61f01bb | ||
|
|
f3fa69e229 | ||
|
|
e2fb22ade0 | ||
|
|
7fb8560908 | ||
|
|
ff7814360e | ||
|
|
2d9303c6ff | ||
|
|
6aee5eb0c7 | ||
|
|
6eb881bffe | ||
|
|
2a5ce95d99 | ||
|
|
bd4fdd8f2e | ||
|
|
09379abd5d | ||
|
|
c6906120d8 | ||
|
|
c4c60933f4 | ||
|
|
a3979cda9c | ||
|
|
3c8ee86e23 | ||
|
|
921c0174fb | ||
|
|
4196d96adc | ||
|
|
743e99d12d | ||
|
|
6beeb23d10 | ||
|
|
838fad916d | ||
|
|
935e89bd93 |
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
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
68
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,68 +0,0 @@
|
||||
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.
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -4,18 +4,23 @@ about: Suggest an idea for TiddlyWiki 5
|
||||
title: "[IDEA]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
type: feature
|
||||
type: idea
|
||||
|
||||
---
|
||||
|
||||
**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 [...]
|
||||
**Is your idea related to a problem? Please describe.**
|
||||
|
||||
A clear and concise description of what the problem is. Eg:
|
||||
As a user, I would like [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
30
core-server/utils/base64.js
Normal file
30
core-server/utils/base64.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
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));
|
||||
@@ -5,3 +5,4 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
|
||||
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
||||
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
||||
* [[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]]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/
|
||||
|
||||
Alerts: Alerts
|
||||
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
|
||||
BinaryWarning/Prompt: This tiddler contains binary data
|
||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.
|
||||
@@ -29,6 +30,7 @@ Error/DeserializeOperator/MissingOperand: Filter Error: Missing operand for 'des
|
||||
Error/DeserializeOperator/UnknownDeserializer: Filter Error: Unknown deserializer provided as operand for the 'deserialize' operator
|
||||
Error/Filter: Filter error
|
||||
Error/FilterSyntax: Syntax error in filter expression
|
||||
Error/FilterPragma: Filter Error: Unknown filter pragma
|
||||
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
||||
Error/IsFilterOperator: Filter Error: Unknown parameter for the 'is' filter operator
|
||||
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
||||
|
||||
@@ -3,6 +3,7 @@ title: $:/language/Search/
|
||||
DefaultResults/Caption: List
|
||||
Filter/Caption: Filter
|
||||
Filter/Hint: Search via a [[filter expression|https://tiddlywiki.com/static/Filters.html]]
|
||||
Filter/AllowDuplicates: Allow duplicate results
|
||||
Filter/Matches: //<small><<resultCount>> matches</small>//
|
||||
Matches: //<small><<resultCount>> matches</small>//
|
||||
Matches/All: All matches:
|
||||
|
||||
@@ -146,14 +146,16 @@ exports.parseFilter = function(filterString) {
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
// Groups:
|
||||
// 1 - entire filter run prefix
|
||||
// 2 - filter run prefix itself
|
||||
// 3 - filter run prefix suffixes
|
||||
// 4 - opening square bracket following filter run prefix
|
||||
// 5 - double quoted string following filter run prefix
|
||||
// 6 - single quoted string following filter run prefix
|
||||
// 7 - anything except for whitespace and square brackets
|
||||
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
// 1 - pragma
|
||||
// 2 - pragma suffix
|
||||
// 3 - entire filter run prefix
|
||||
// 4 - filter run prefix name
|
||||
// 5 - filter run prefix suffixes
|
||||
// 6 - opening square bracket following filter run prefix
|
||||
// 7 - double quoted string following filter run prefix
|
||||
// 8 - single quoted string following filter run prefix
|
||||
// 9 - anything except for whitespace and square brackets
|
||||
operandRegExp = /(?:::(\w+)(?:\:(\w+))?(?=\s|$)|((?:\+|\-|~|(?:=>?)|:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+)))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -170,18 +172,23 @@ exports.parseFilter = function(filterString) {
|
||||
};
|
||||
match = operandRegExp.exec(filterString);
|
||||
if(match && match.index === p) {
|
||||
// If there is a filter run prefix
|
||||
if(match[1]) {
|
||||
operation.prefix = match[1];
|
||||
// If there is a filter pragma
|
||||
operation.pragma = match[1];
|
||||
operation.suffix = match[2];
|
||||
p = match.index + match[0].length;
|
||||
} else if(match[3]) {
|
||||
// If there is a filter run prefix
|
||||
operation.prefix = match[3];
|
||||
p = p + operation.prefix.length;
|
||||
// Name for named prefixes
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
if(match[4]) {
|
||||
operation.namedPrefix = match[4];
|
||||
}
|
||||
// Suffixes for filter run prefix
|
||||
if(match[3]) {
|
||||
if(match[5]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||
$tw.utils.each(match[5].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
@@ -193,7 +200,7 @@ exports.parseFilter = function(filterString) {
|
||||
}
|
||||
}
|
||||
// Opening square bracket
|
||||
if(match[4]) {
|
||||
if(match[6]) {
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
@@ -203,9 +210,9 @@ exports.parseFilter = function(filterString) {
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
}
|
||||
// Quoted strings and unquoted title
|
||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||
if(match[7] || match[8] || match[9]) { // Double quoted string, single quoted string or unquoted title
|
||||
operation.operators.push(
|
||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||
{operator: "title", operands: [{text: match[7] || match[8] || match[9]}]}
|
||||
);
|
||||
}
|
||||
results.push(operation);
|
||||
@@ -230,8 +237,8 @@ exports.getFilterRunPrefixes = function() {
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
exports.filterTiddlers = function(filterString,widget,source,options) {
|
||||
var fn = this.compileFilter(filterString,options);
|
||||
try {
|
||||
const fnResult = fn.call(this,source,widget);
|
||||
return fnResult;
|
||||
@@ -241,17 +248,21 @@ exports.filterTiddlers = function(filterString,widget,source) {
|
||||
};
|
||||
|
||||
/*
|
||||
Compile a filter into a function with the signature fn(source,widget) where:
|
||||
Compile a filter into a function with the signature fn(source,widget,options) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
options: optional hashmap of options
|
||||
options.defaultFilterRunPrefix: the default filter run prefix to use when none is specified
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
exports.compileFilter = function(filterString,options) {
|
||||
var defaultFilterRunPrefix = (options || {}).defaultFilterRunPrefix || "or";
|
||||
var cacheKey = filterString + "|" + defaultFilterRunPrefix;
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
if(this.filterCache[filterString] !== undefined) {
|
||||
return this.filterCache[filterString];
|
||||
if(this.filterCache[cacheKey] !== undefined) {
|
||||
return this.filterCache[cacheKey];
|
||||
}
|
||||
var filterParseTree;
|
||||
try {
|
||||
@@ -330,7 +341,8 @@ exports.compileFilter = function(filterString) {
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
widget: widget,
|
||||
defaultFilterRunPrefix: defaultFilterRunPrefix
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
@@ -351,29 +363,45 @@ exports.compileFilter = function(filterString) {
|
||||
var filterRunPrefixes = self.getFilterRunPrefixes();
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
if(operation.pragma) {
|
||||
switch(operation.pragma) {
|
||||
case "defaultprefix":
|
||||
defaultFilterRunPrefix = operation.suffix || "or";
|
||||
break;
|
||||
default:
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
results.push($tw.language.getString("Error/FilterPragma"));
|
||||
};
|
||||
}
|
||||
}
|
||||
return function(results,source,widget) {
|
||||
// Dummy response
|
||||
};
|
||||
} else {
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // Use the default filter run prefix if none is specified
|
||||
return filterRunPrefixes[defaultFilterRunPrefix](operationSubFunction, options);
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
@@ -412,7 +440,7 @@ exports.compileFilter = function(filterString) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
this.filterCache[filterString] = fnMeasured;
|
||||
this.filterCache[cacheKey] = fnMeasured;
|
||||
this.filterCacheCount++;
|
||||
return fnMeasured;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,8 @@ exports.enlist = function(source,operator,options) {
|
||||
var allowDuplicates = false;
|
||||
switch(operator.suffix) {
|
||||
case "raw":
|
||||
// Intentional fallthrough
|
||||
case "all":
|
||||
allowDuplicates = true;
|
||||
break;
|
||||
case "dedupe":
|
||||
|
||||
@@ -13,7 +13,9 @@ Filter operator returning those input titles that pass a subfilter
|
||||
Export our filter function
|
||||
*/
|
||||
exports.filter = function(source,operator,options) {
|
||||
var filterFn = options.wiki.compileFilter(operator.operand),
|
||||
var suffixes = operator.suffixes || [],
|
||||
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or",
|
||||
filterFn = options.wiki.compileFilter(operator.operand,{defaultFilterRunPrefix}),
|
||||
results = [],
|
||||
target = operator.prefix !== "!";
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -14,31 +14,31 @@ Export our filter function
|
||||
*/
|
||||
exports.sort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortan = function(source, operator, options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
|
||||
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
|
||||
operand = (operator.operand || ""),
|
||||
fnCalc;
|
||||
if(suffix === "prefix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];};
|
||||
} else if(suffix === "suffix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];};
|
||||
} else {
|
||||
if(operand === "") {
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];}
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];};
|
||||
} else {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];};
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
@@ -58,7 +58,7 @@ exports.split = makeStringBinaryOperator(
|
||||
);
|
||||
|
||||
exports["enlist-input"] = makeStringBinaryOperator(
|
||||
function(a,o,s) {return $tw.utils.parseStringArray("" + a,(s === "raw"));}
|
||||
function(a,o,s) {return $tw.utils.parseStringArray("" + a,(s === "raw" || s === "all"));}
|
||||
);
|
||||
|
||||
exports.join = makeStringReducingOperator(
|
||||
@@ -71,107 +71,53 @@ exports.join = makeStringReducingOperator(
|
||||
},null
|
||||
);
|
||||
|
||||
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
|
||||
exports.levenshtein = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
diffs = dmpObject.diff_main(a,b);
|
||||
return [dmpObject.diff_levenshtein(diffs) + ""];
|
||||
const diffs = dmp.diffMain(a,b);
|
||||
return [dmp.diffLevenshtein(diffs).toString()];
|
||||
}
|
||||
);
|
||||
|
||||
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
function diffLineWordMode(text1,text2,mode) {
|
||||
var dmpObject = new dmp.diff_match_patch();
|
||||
var a = diffPartsToChars(text1,text2,mode);
|
||||
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
|
||||
var lineText1 = a.chars1;
|
||||
var lineText2 = a.chars2;
|
||||
var lineArray = a.lineArray;
|
||||
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
||||
dmpObject.diff_charsToLines_(diffs,lineArray);
|
||||
var diffs = dmp.diffMain(lineText1,lineText2,false);
|
||||
dmp.diffCharsToLines(diffs,lineArray);
|
||||
return diffs;
|
||||
}
|
||||
|
||||
function diffPartsToChars(text1,text2,mode) {
|
||||
var lineArray = [];
|
||||
var lineHash = {};
|
||||
lineArray[0] = '';
|
||||
|
||||
function diff_linesToPartsMunge_(text,mode) {
|
||||
var chars = '';
|
||||
var lineStart = 0;
|
||||
var lineEnd = -1;
|
||||
var lineArrayLength = lineArray.length,
|
||||
regexpResult;
|
||||
var searchRegexp = /\W+/g;
|
||||
while(lineEnd < text.length - 1) {
|
||||
if(mode === "words") {
|
||||
regexpResult = searchRegexp.exec(text);
|
||||
lineEnd = searchRegexp.lastIndex;
|
||||
if(regexpResult === null) {
|
||||
lineEnd = text.length;
|
||||
}
|
||||
lineEnd = --lineEnd;
|
||||
} else {
|
||||
lineEnd = text.indexOf('\n', lineStart);
|
||||
if(lineEnd == -1) {
|
||||
lineEnd = text.length - 1;
|
||||
}
|
||||
}
|
||||
var line = text.substring(lineStart, lineEnd + 1);
|
||||
|
||||
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
||||
chars += String.fromCharCode(lineHash[line]);
|
||||
} else {
|
||||
if(lineArrayLength == maxLines) {
|
||||
line = text.substring(lineStart);
|
||||
lineEnd = text.length;
|
||||
}
|
||||
chars += String.fromCharCode(lineArrayLength);
|
||||
lineHash[line] = lineArrayLength;
|
||||
lineArray[lineArrayLength++] = line;
|
||||
}
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
var maxLines = 40000;
|
||||
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||
maxLines = 65535;
|
||||
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
||||
};
|
||||
|
||||
exports.makepatches = function(source,operator,options) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
suffix = operator.suffix || "",
|
||||
var suffix = operator.suffix || "",
|
||||
result = [];
|
||||
|
||||
source(function(tiddler,title) {
|
||||
var diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmpObject.patch_make(title,diffs);
|
||||
} else {
|
||||
patches = dmpObject.patch_make(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
||||
});
|
||||
source(function(tiddler,title) {
|
||||
let diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmp.patchMake(title,diffs);
|
||||
} else {
|
||||
patches = dmp.patchMake(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.applypatches = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
patches;
|
||||
let patches;
|
||||
try {
|
||||
patches = dmpObject.patch_fromText(b);
|
||||
patches = dmp.patchFromText(b);
|
||||
} catch(e) {
|
||||
}
|
||||
if(patches) {
|
||||
return [dmpObject.patch_apply(patches,a)[0]];
|
||||
return [dmp.patchApply(patches,a)[0]];
|
||||
} else {
|
||||
return [a];
|
||||
}
|
||||
@@ -279,7 +225,7 @@ exports.pad = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
exports.charcode = function(source,operator,options) {
|
||||
var chars = [];
|
||||
|
||||
@@ -13,7 +13,9 @@ Filter operator returning its operand evaluated as a filter
|
||||
Export our filter function
|
||||
*/
|
||||
exports.subfilter = function(source,operator,options) {
|
||||
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source);
|
||||
var suffixes = operator.suffixes || [],
|
||||
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or";
|
||||
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source,{defaultFilterRunPrefix});
|
||||
if(operator.prefix === "!") {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -11,17 +11,16 @@ The image parser parses an image into an embeddable HTML element
|
||||
|
||||
var ImageParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "img",
|
||||
attributes: {}
|
||||
};
|
||||
type: "image",
|
||||
attributes: {}
|
||||
};
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
element.attributes.source = {type: "string", value: options._canonical_uri};
|
||||
} else if(text) {
|
||||
if(type === "image/svg+xml" || type === ".svg") {
|
||||
element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||
element.attributes.source = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||
} else {
|
||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
element.attributes.source = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
}
|
||||
}
|
||||
this.tree = [element];
|
||||
|
||||
@@ -18,7 +18,6 @@ exports.synchronous = true;
|
||||
// Default story and history lists
|
||||
var PAGE_TITLE_TITLE = "$:/core/wiki/title";
|
||||
var PAGE_STYLESHEET_TITLE = "$:/core/ui/PageStylesheet";
|
||||
var ROOT_STYLESHEET_TITLE = "$:/core/ui/RootStylesheet";
|
||||
var PAGE_TEMPLATE_TITLE = "$:/core/ui/RootTemplate";
|
||||
|
||||
// Time (in ms) that we defer refreshing changes to draft tiddlers
|
||||
@@ -45,13 +44,22 @@ exports.startup = function() {
|
||||
publishTitle();
|
||||
}
|
||||
});
|
||||
|
||||
var styleParser = $tw.wiki.parseTiddler(ROOT_STYLESHEET_TITLE,{parseAsInline: true}),
|
||||
styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: document});
|
||||
styleWidgetNode.render(document.head,null);
|
||||
|
||||
// Set up the styles
|
||||
$tw.styleWidgetNode = $tw.wiki.makeTranscludeWidget(PAGE_STYLESHEET_TITLE,{document: $tw.fakeDocument});
|
||||
$tw.styleContainer = $tw.fakeDocument.createElement("style");
|
||||
$tw.styleWidgetNode.render($tw.styleContainer,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) {
|
||||
styleWidgetNode.refresh(changes,document.head,null);
|
||||
if($tw.styleWidgetNode.refresh(changes,$tw.styleContainer,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
|
||||
$tw.perf.report("mainRender",function() {
|
||||
@@ -60,7 +68,7 @@ exports.startup = function() {
|
||||
$tw.utils.addClass($tw.pageContainer,"tc-page-container-wrapper");
|
||||
document.body.insertBefore($tw.pageContainer,document.body.firstChild);
|
||||
$tw.pageWidgetNode.render($tw.pageContainer,null);
|
||||
$tw.hooks.invokeHook("th-page-refreshed");
|
||||
$tw.hooks.invokeHook("th-page-refreshed");
|
||||
})();
|
||||
// Remove any splash screen elements
|
||||
var removeList = document.querySelectorAll(".tc-remove-when-wiki-loaded");
|
||||
|
||||
@@ -63,16 +63,24 @@ exports.startup = function() {
|
||||
$tw.eventBus.emit("window:closed",{windowID});
|
||||
},false);
|
||||
// Set up the styles
|
||||
var styleParser = $tw.wiki.parseTiddler("$:/core/ui/RootStylesheet",{parseAsInline: true}),
|
||||
styleWidgetNode = $tw.wiki.makeWidget(styleParser,{document: srcDocument});
|
||||
styleWidgetNode.render(srcDocument.head,null);
|
||||
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{
|
||||
document: $tw.fakeDocument,
|
||||
variables: variables,
|
||||
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
|
||||
var parser = $tw.wiki.parseTiddler(template),
|
||||
widgetNode = $tw.wiki.makeWidget(parser,{document: srcDocument, parentWidget: $tw.rootWidget, variables: variables});
|
||||
widgetNode.render(srcDocument.body,srcDocument.body.firstChild);
|
||||
// Function to handle refreshes
|
||||
refreshHandler = function(changes) {
|
||||
styleWidgetNode.refresh(changes);
|
||||
if(styleWidgetNode.refresh(changes,styleContainer,null)) {
|
||||
styleElement.innerHTML = styleContainer.textContent;
|
||||
}
|
||||
widgetNode.refresh(changes);
|
||||
};
|
||||
$tw.wiki.addEventListener("change",refreshHandler);
|
||||
|
||||
31
core/modules/utils/base64.js
Normal file
31
core/modules/utils/base64.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/*\
|
||||
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));
|
||||
@@ -44,15 +44,15 @@ exports.domMatchesSelector = (node,selector) => node.matches(selector);
|
||||
exports.hasClass = (el,className) => el.classList && el.classList.contains(className);
|
||||
|
||||
exports.addClass = function(el,className) {
|
||||
el.classList && el.classList.add(className);
|
||||
el.classList && className && el.classList.add(className);
|
||||
};
|
||||
|
||||
exports.removeClass = function(el,className) {
|
||||
el.classList && el.classList.remove(className);
|
||||
el.classList && className && el.classList.remove(className);
|
||||
};
|
||||
|
||||
exports.toggleClass = function(el,className,status) {
|
||||
el.classList && el.classList.toggle(className, status);
|
||||
el.classList && className && el.classList.toggle(className, status);
|
||||
};
|
||||
|
||||
exports.getLocationPath = () => window.location.origin + window.location.pathname;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ Return the dflt (default) parameter if str is not a base-10 number.
|
||||
exports.getInt = function(str,deflt) {
|
||||
var i = parseInt(str,10);
|
||||
return isNaN(i) ? deflt : i;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Repeatedly replaces a substring within a string. Like String.prototype.replace, but without any of the default special handling of $ sequences in the replace string
|
||||
@@ -69,12 +69,12 @@ exports.replaceString = function(text,search,replace) {
|
||||
exports.trimPrefix = function(str,unwanted) {
|
||||
if(typeof str === "string" && typeof unwanted === "string") {
|
||||
if(unwanted === "") {
|
||||
return str.replace(/^\s\s*/, '');
|
||||
return str.replace(/^\s\s*/, "");
|
||||
} else {
|
||||
// Safely regexp-escape the unwanted text
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
var regex = new RegExp('^(' + unwanted + ')+');
|
||||
return str.replace(regex, '');
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
var regex = new RegExp("^(" + unwanted + ")+");
|
||||
return str.replace(regex, "");
|
||||
}
|
||||
} else {
|
||||
return str;
|
||||
@@ -84,12 +84,12 @@ exports.trimPrefix = function(str,unwanted) {
|
||||
exports.trimSuffix = function(str,unwanted) {
|
||||
if(typeof str === "string" && typeof unwanted === "string") {
|
||||
if(unwanted === "") {
|
||||
return str.replace(/\s\s*$/, '');
|
||||
return str.replace(/\s\s*$/, "");
|
||||
} else {
|
||||
// Safely regexp-escape the unwanted text
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
var regex = new RegExp('(' + unwanted + ')+$');
|
||||
return str.replace(regex, '');
|
||||
unwanted = unwanted.replace(/[\\^$*+?.()|[\]{}]/g, "\\$&");
|
||||
var regex = new RegExp("(" + unwanted + ")+$");
|
||||
return str.replace(regex, "");
|
||||
}
|
||||
} else {
|
||||
return str;
|
||||
@@ -101,14 +101,14 @@ Convert a string to sentence case (ie capitalise first letter)
|
||||
*/
|
||||
exports.toSentenceCase = function(str) {
|
||||
return (str || "").replace(/^\S/, function(c) {return c.toUpperCase();});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a string to title case (ie capitalise each initial letter)
|
||||
*/
|
||||
exports.toTitleCase = function(str) {
|
||||
return (str || "").replace(/(^|\s)\S/g, function(c) {return c.toUpperCase();});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Find the line break preceding a given position in a string
|
||||
@@ -358,8 +358,8 @@ exports.formatDateString = function(date,template) {
|
||||
}],
|
||||
[/^TZD/, function() {
|
||||
var tz = date.getTimezoneOffset(),
|
||||
atz = Math.abs(tz);
|
||||
return (tz < 0 ? '+' : '-') + $tw.utils.pad(Math.floor(atz / 60)) + ':' + $tw.utils.pad(atz % 60);
|
||||
atz = Math.abs(tz);
|
||||
return (tz < 0 ? "+" : "-") + $tw.utils.pad(Math.floor(atz / 60)) + ":" + $tw.utils.pad(atz % 60);
|
||||
}],
|
||||
[/^wYY/, function() {
|
||||
return $tw.utils.pad($tw.utils.getYearForWeekNo(date) - 2000);
|
||||
@@ -568,9 +568,9 @@ exports.unescapeLineBreaks = function(s) {
|
||||
exports.escape = function(ch) {
|
||||
var charCode = ch.charCodeAt(0);
|
||||
if(charCode <= 0xFF) {
|
||||
return '\\x' + $tw.utils.pad(charCode.toString(16).toUpperCase());
|
||||
return "\\x" + $tw.utils.pad(charCode.toString(16).toUpperCase());
|
||||
} else {
|
||||
return '\\u' + $tw.utils.pad(charCode.toString(16).toUpperCase(),4);
|
||||
return "\\u" + $tw.utils.pad(charCode.toString(16).toUpperCase(),4);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -587,11 +587,11 @@ exports.stringify = function(s, rawUnicode) {
|
||||
*/
|
||||
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
|
||||
return (s || "")
|
||||
.replace(/\\/g, '\\\\') // backslash
|
||||
.replace(/\\/g, "\\\\") // backslash
|
||||
.replace(/"/g, '\\"') // double quote character
|
||||
.replace(/'/g, "\\'") // single quote character
|
||||
.replace(/\r/g, '\\r') // carriage return
|
||||
.replace(/\n/g, '\\n') // line feed
|
||||
.replace(/\r/g, "\\r") // carriage return
|
||||
.replace(/\n/g, "\\n") // line feed
|
||||
.replace(regex, exports.escape); // non-ASCII characters
|
||||
};
|
||||
|
||||
@@ -601,15 +601,15 @@ exports.jsonStringify = function(s, rawUnicode) {
|
||||
// See http://www.json.org/
|
||||
var regex = rawUnicode ? /[\x00-\x1f]/g : /[\x00-\x1f\x80-\uFFFF]/g;
|
||||
return (s || "")
|
||||
.replace(/\\/g, '\\\\') // backslash
|
||||
.replace(/\\/g, "\\\\") // backslash
|
||||
.replace(/"/g, '\\"') // double quote character
|
||||
.replace(/\r/g, '\\r') // carriage return
|
||||
.replace(/\n/g, '\\n') // line feed
|
||||
.replace(/\x08/g, '\\b') // backspace
|
||||
.replace(/\x0c/g, '\\f') // formfeed
|
||||
.replace(/\t/g, '\\t') // tab
|
||||
.replace(/\r/g, "\\r") // carriage return
|
||||
.replace(/\n/g, "\\n") // line feed
|
||||
.replace(/\x08/g, "\\b") // backspace
|
||||
.replace(/\x0c/g, "\\f") // formfeed
|
||||
.replace(/\t/g, "\\t") // tab
|
||||
.replace(regex,function(s) {
|
||||
return '\\u' + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
|
||||
return "\\u" + $tw.utils.pad(s.charCodeAt(0).toString(16).toUpperCase(),4);
|
||||
}); // non-ASCII characters
|
||||
};
|
||||
|
||||
@@ -617,7 +617,7 @@ exports.jsonStringify = function(s, rawUnicode) {
|
||||
Escape the RegExp special characters with a preceding backslash
|
||||
*/
|
||||
exports.escapeRegExp = function(s) {
|
||||
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, '\\$&');
|
||||
return s.replace(/[\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}]/g, "\\$&");
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -700,7 +700,7 @@ exports.parseTextReference = function(textRef) {
|
||||
}
|
||||
} else {
|
||||
// If we couldn't parse it
|
||||
result.title = textRef
|
||||
result.title = textRef;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -759,60 +759,17 @@ Cryptographic hash function as used by sha256 filter operator
|
||||
options.length .. number of characters returned defaults to 64
|
||||
*/
|
||||
exports.sha256 = function(str, options) {
|
||||
options = options || {}
|
||||
options = options || {};
|
||||
return $tw.sjcl.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(str)).substr(0,options.length || 64);
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
*/
|
||||
exports.base64Decode = function(string64,binary,urlsafe) {
|
||||
const encoded = urlsafe ? string64.replace(/_/g,'/').replace(/-/g,'+') : string64;
|
||||
if(binary) return exports.atob(encoded)
|
||||
else return exports.base64DecodeUtf8(encoded);
|
||||
const encoded = urlsafe ? string64.replace(/_/g,"/").replace(/-/g,"+") : string64;
|
||||
if(binary) return $tw.utils.atob(encoded);
|
||||
else return $tw.utils.base64DecodeUtf8(encoded);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -820,10 +777,10 @@ Encode a string to base64
|
||||
*/
|
||||
exports.base64Encode = function(string64,binary,urlsafe) {
|
||||
let encoded;
|
||||
if(binary) encoded = exports.btoa(string64);
|
||||
else encoded = exports.base64EncodeUtf8(string64);
|
||||
if(binary) encoded = $tw.utils.btoa(string64);
|
||||
else encoded = $tw.utils.base64EncodeUtf8(string64);
|
||||
if(urlsafe) {
|
||||
encoded = encoded.replace(/\+/g,'-').replace(/\//g,'_');
|
||||
encoded = encoded.replace(/\+/g,"-").replace(/\//g,"_");
|
||||
}
|
||||
return encoded;
|
||||
};
|
||||
@@ -957,3 +914,56 @@ exports.makeCompareFunction = function(type,options) {
|
||||
};
|
||||
return (types[type] || types[options.defaultType] || types.number);
|
||||
};
|
||||
|
||||
/*
|
||||
Split text into parts (lines or words) for diff operations
|
||||
Adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
*/
|
||||
exports.diffPartsToChars = function(text1,text2,mode) {
|
||||
const lineArray = [""],
|
||||
lineHash = Object.create(null);
|
||||
|
||||
function diff_linesToPartsMunge_(text,mode) {
|
||||
let chars = "",
|
||||
lineStart = 0,
|
||||
lineEnd = -1,
|
||||
lineArrayLength = lineArray.length,
|
||||
regexpResult;
|
||||
const searchRegexp = /\W+/g;
|
||||
while(lineEnd < text.length - 1) {
|
||||
if(mode === "words") {
|
||||
regexpResult = searchRegexp.exec(text);
|
||||
lineEnd = searchRegexp.lastIndex;
|
||||
if(regexpResult === null) {
|
||||
lineEnd = text.length;
|
||||
}
|
||||
lineEnd = --lineEnd;
|
||||
} else {
|
||||
lineEnd = text.indexOf("\n", lineStart);
|
||||
if(lineEnd === -1) {
|
||||
lineEnd = text.length - 1;
|
||||
}
|
||||
}
|
||||
let line = text.substring(lineStart, lineEnd + 1);
|
||||
|
||||
if(line in lineHash) {
|
||||
chars += String.fromCharCode(lineHash[line]);
|
||||
} else {
|
||||
if(lineArrayLength === maxLines) {
|
||||
line = text.substring(lineStart);
|
||||
lineEnd = text.length;
|
||||
}
|
||||
chars += String.fromCharCode(lineArrayLength);
|
||||
lineHash[line] = lineArrayLength;
|
||||
lineArray[lineArrayLength++] = line;
|
||||
}
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
let maxLines = 40000;
|
||||
const chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||
maxLines = 65535;
|
||||
const chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||
return {chars1, chars2, lineArray};
|
||||
};
|
||||
|
||||
@@ -62,8 +62,8 @@ SendMessageWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var paramObject = Object.create(null);
|
||||
// Add names/values pairs if present
|
||||
if(this.actionNames && this.actionValues) {
|
||||
var names = this.wiki.filterTiddlers(this.actionNames,this),
|
||||
values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
var names = this.wiki.filterTiddlers(this.actionNames,this,{defaultFilterRunPrefix: "all"}),
|
||||
values = this.wiki.filterTiddlers(this.actionValues,this,{defaultFilterRunPrefix: "all"});
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
paramObject[name] = values[index] || "";
|
||||
});
|
||||
|
||||
@@ -56,10 +56,10 @@ Invoke the action associated with this widget
|
||||
*/
|
||||
SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var tiddler = this.wiki.getTiddler(this.actionTiddler),
|
||||
names, values = this.wiki.filterTiddlers(this.actionValues,this);
|
||||
names, values = this.wiki.filterTiddlers(this.actionValues,this,{defaultFilterRunPrefix: "all"});
|
||||
if(this.actionFields) {
|
||||
var additions = {};
|
||||
names = this.wiki.filterTiddlers(this.actionFields,this);
|
||||
names = this.wiki.filterTiddlers(this.actionFields,this,{defaultFilterRunPrefix: "all"});
|
||||
$tw.utils.each(names,function(fieldname,index) {
|
||||
additions[fieldname] = values[index] || "";
|
||||
});
|
||||
@@ -68,7 +68,7 @@ SetMultipleFieldsWidget.prototype.invokeAction = function(triggeringWidget,event
|
||||
this.wiki.addTiddler(new $tw.Tiddler(creationFields,tiddler,{title: this.actionTiddler},modificationFields,additions));
|
||||
} else if(this.actionIndexes) {
|
||||
var data = this.wiki.getTiddlerData(this.actionTiddler,Object.create(null));
|
||||
names = this.wiki.filterTiddlers(this.actionIndexes,this);
|
||||
names = this.wiki.filterTiddlers(this.actionIndexes,this,{defaultFilterRunPrefix: "all"});
|
||||
$tw.utils.each(names,function(name,index) {
|
||||
data[name] = values[index] || "";
|
||||
});
|
||||
|
||||
@@ -9,6 +9,8 @@ Button widget
|
||||
|
||||
"use strict";
|
||||
|
||||
const ALLOWED_SELECTED_ARIA_ATTR = ["aria-checked", "aria-selected", "aria-pressed"];
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var Popup = require("$:/core/modules/utils/dom/popup.js");
|
||||
@@ -44,9 +46,14 @@ ButtonWidget.prototype.render = function(parent,nextSibling) {
|
||||
var classes = this["class"].split(" ") || [],
|
||||
isPoppedUp = (this.popup || this.popupTitle) && this.isPoppedUp();
|
||||
if(this.selectedClass) {
|
||||
if((this.set || this.setTitle) && this.setTo && this.isSelected()) {
|
||||
$tw.utils.pushTop(classes, this.selectedClass.split(" "));
|
||||
domNode.setAttribute("aria-checked", "true");
|
||||
if((this.set || this.setTitle) && this.setTo) {
|
||||
const selectedAria = ALLOWED_SELECTED_ARIA_ATTR.includes(this.selectedAria) ? this.selectedAria : "aria-checked";
|
||||
if(this.isSelected()) {
|
||||
$tw.utils.pushTop(classes, this.selectedClass.split(" "));
|
||||
domNode.setAttribute(selectedAria, "true");
|
||||
} else {
|
||||
domNode.setAttribute(selectedAria, "false");
|
||||
}
|
||||
}
|
||||
if(isPoppedUp) {
|
||||
$tw.utils.pushTop(classes,this.selectedClass.split(" "));
|
||||
@@ -221,6 +228,7 @@ ButtonWidget.prototype.execute = function() {
|
||||
this.style = this.getAttribute("style");
|
||||
this["class"] = this.getAttribute("class","");
|
||||
this.selectedClass = this.getAttribute("selectedClass");
|
||||
this.selectedAria = this.getAttribute("selectedAria");
|
||||
this.defaultSetValue = this.getAttribute("default","");
|
||||
this.buttonTag = this.getAttribute("tag");
|
||||
this.dragTiddler = this.getAttribute("dragTiddler");
|
||||
|
||||
@@ -9,8 +9,8 @@ Widget to display a diff between two texts
|
||||
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget,
|
||||
dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
|
||||
var DiffTextWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
@@ -35,19 +35,24 @@ DiffTextWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
// Create the diff object
|
||||
var dmpObject = new dmp.diff_match_patch();
|
||||
dmpObject.Diff_EditCost = $tw.utils.parseNumber(this.getAttribute("editcost","4"));
|
||||
var diffs = dmpObject.diff_main(this.getAttribute("source",""),this.getAttribute("dest",""));
|
||||
const editCost = $tw.utils.parseNumber(this.getAttribute("editcost","4"));
|
||||
const mode = this.getAttribute("mode") || "chars";
|
||||
let diffs;
|
||||
if(mode === "lines" || mode === "words") {
|
||||
diffs = diffLineWordMode(this.getAttribute("source",""),this.getAttribute("dest",""),mode,editCost);
|
||||
} else {
|
||||
diffs = dmp.diffMain(this.getAttribute("source",""),this.getAttribute("dest",""),{diffEditCost: editCost});
|
||||
}
|
||||
// Apply required cleanup
|
||||
switch(this.getAttribute("cleanup","semantic")) {
|
||||
case "none":
|
||||
// No cleanup
|
||||
break;
|
||||
case "efficiency":
|
||||
dmpObject.diff_cleanupEfficiency(diffs);
|
||||
dmp.diffCleanupEfficiency(diffs, {diffEditCost: editCost});
|
||||
break;
|
||||
default: // case "semantic"
|
||||
dmpObject.diff_cleanupSemantic(diffs);
|
||||
dmp.diffCleanupSemantic(diffs);
|
||||
break;
|
||||
}
|
||||
// Create the elements
|
||||
@@ -133,7 +138,7 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of
|
||||
*/
|
||||
DiffTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.editcost) {
|
||||
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup || changedAttributes.mode || changedAttributes.editcost) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else {
|
||||
@@ -141,4 +146,15 @@ DiffTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
}
|
||||
};
|
||||
|
||||
// This function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
function diffLineWordMode(text1,text2,mode,editCost) {
|
||||
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
|
||||
var lineText1 = a.chars1;
|
||||
var lineText2 = a.chars2;
|
||||
var lineArray = a.lineArray;
|
||||
var diffs = dmp.diffMain(lineText1,lineText2,{diffEditCost: editCost});
|
||||
dmp.diffCharsToLines(diffs,lineArray);
|
||||
return diffs;
|
||||
}
|
||||
|
||||
exports["diff-text"] = DiffTextWidget;
|
||||
|
||||
@@ -72,8 +72,8 @@ GenesisWidget.prototype.execute = function() {
|
||||
this.attributeNames = [];
|
||||
this.attributeValues = [];
|
||||
if(this.genesisNames && this.genesisValues) {
|
||||
this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this);
|
||||
this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this);
|
||||
this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this,{defaultFilterRunPrefix: "all"});
|
||||
this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this,{defaultFilterRunPrefix: "all"});
|
||||
$tw.utils.each(this.attributeNames,function(varname,index) {
|
||||
$tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || "");
|
||||
});
|
||||
@@ -103,8 +103,8 @@ GenesisWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes(),
|
||||
filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values",""),
|
||||
attributeNames = this.wiki.filterTiddlers(filterNames,this),
|
||||
attributeValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
attributeNames = this.wiki.filterTiddlers(filterNames,this,{defaultFilterRunPrefix: "all"}),
|
||||
attributeValues = this.wiki.filterTiddlers(filterValues,this,{defaultFilterRunPrefix: "all"});
|
||||
if($tw.utils.count(changedAttributes) > 0 || !$tw.utils.isArrayEqual(this.attributeNames,attributeNames) || !$tw.utils.isArrayEqual(this.attributeValues,attributeValues)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
|
||||
@@ -12,7 +12,7 @@ Widget to set multiple variables at once from a list of names and a list of valu
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var SetMultipleVariablesWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -24,52 +24,52 @@ SetMultipleVariablesWidget.prototype = new Widget();
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.execute = function() {
|
||||
// Setup our variables
|
||||
this.setVariables();
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
// Setup our variables
|
||||
this.setVariables();
|
||||
// Construct the child widgets
|
||||
this.makeChildWidgets();
|
||||
};
|
||||
|
||||
|
||||
SetMultipleVariablesWidget.prototype.setVariables = function() {
|
||||
// Set the variables
|
||||
var self = this,
|
||||
filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values","");
|
||||
this.variableNames = [];
|
||||
this.variableValues = [];
|
||||
if(filterNames && filterValues) {
|
||||
this.variableNames = this.wiki.filterTiddlers(filterNames,this);
|
||||
this.variableValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
$tw.utils.each(this.variableNames,function(varname,index) {
|
||||
self.setVariable(varname,self.variableValues[index]);
|
||||
});
|
||||
}
|
||||
// Set the variables
|
||||
var self = this,
|
||||
filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values","");
|
||||
this.variableNames = [];
|
||||
this.variableValues = [];
|
||||
if(filterNames && filterValues) {
|
||||
this.variableNames = this.wiki.filterTiddlers(filterNames,this,{defaultFilterRunPrefix: "all"});
|
||||
this.variableValues = this.wiki.filterTiddlers(filterValues,this,{defaultFilterRunPrefix: "all"});
|
||||
$tw.utils.each(this.variableNames,function(varname,index) {
|
||||
self.setVariable(varname,self.variableValues[index]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
SetMultipleVariablesWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values",""),
|
||||
variableNames = this.wiki.filterTiddlers(filterNames,this),
|
||||
variableValues = this.wiki.filterTiddlers(filterValues,this);
|
||||
if(!$tw.utils.isArrayEqual(this.variableNames,variableNames) || !$tw.utils.isArrayEqual(this.variableValues,variableValues)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
var filterNames = this.getAttribute("$names",""),
|
||||
filterValues = this.getAttribute("$values",""),
|
||||
variableNames = this.wiki.filterTiddlers(filterNames,this,{defaultFilterRunPrefix: "all"}),
|
||||
variableValues = this.wiki.filterTiddlers(filterValues,this,{defaultFilterRunPrefix: "all"});
|
||||
if(!$tw.utils.isArrayEqual(this.variableNames,variableNames) || !$tw.utils.isArrayEqual(this.variableValues,variableValues)) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports["setmultiplevariables"] = SetMultipleVariablesWidget;
|
||||
|
||||
@@ -9,376 +9,215 @@ View widget
|
||||
|
||||
"use strict";
|
||||
|
||||
const Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ViewWidget = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
==========================================
|
||||
ViewHandler Base Class
|
||||
==========================================
|
||||
Base class for all view format handlers.
|
||||
Provides common functionality and defines the interface for subclasses.
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
class ViewHandler {
|
||||
constructor(widget) {
|
||||
this.widget = widget;
|
||||
this.wiki = widget.wiki;
|
||||
this.document = widget.document;
|
||||
this.viewTitle = widget.viewTitle;
|
||||
this.viewField = widget.viewField;
|
||||
this.viewIndex = widget.viewIndex;
|
||||
this.viewSubtiddler = widget.viewSubtiddler;
|
||||
this.viewTemplate = widget.viewTemplate;
|
||||
this.viewMode = widget.viewMode;
|
||||
}
|
||||
|
||||
render(parent, nextSibling) {
|
||||
this.text = this.getValue();
|
||||
this.createTextNode(parent, nextSibling);
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.widget.getValueAsText();
|
||||
}
|
||||
|
||||
createTextNode(parent, nextSibling) {
|
||||
if(this.text) {
|
||||
const textNode = this.document.createTextNode(this.text);
|
||||
parent.insertBefore(textNode, nextSibling);
|
||||
this.widget.domNodes.push(textNode);
|
||||
} else {
|
||||
this.widget.makeChildWidgets();
|
||||
this.widget.renderChildren(parent, nextSibling);
|
||||
}
|
||||
}
|
||||
|
||||
refresh() {
|
||||
var self = this;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ViewWidget.prototype = new Widget();
|
||||
|
||||
/*
|
||||
==========================================
|
||||
Wikified View Handler Base
|
||||
==========================================
|
||||
Base class for wikified view handlers
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
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;
|
||||
ViewWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
if(this.text) {
|
||||
var textNode = this.document.createTextNode(this.text);
|
||||
parent.insertBefore(textNode,nextSibling);
|
||||
this.domNodes.push(textNode);
|
||||
} else {
|
||||
this.makeChildWidgets();
|
||||
this.renderChildren(parent,nextSibling);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
==========================================
|
||||
ViewWidget
|
||||
==========================================
|
||||
Main widget class that orchestrates view handlers
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
class ViewWidget extends Widget {
|
||||
constructor(parseTreeNode, options) {
|
||||
super();
|
||||
this.initialise(parseTreeNode, options);
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
render(parent, nextSibling) {
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
this.viewHandler = ViewHandlerFactory.createHandler(this.viewFormat, this);
|
||||
this.viewHandler.render(parent, nextSibling);
|
||||
}
|
||||
/*
|
||||
The various formatter functions are baked into this widget for the moment. Eventually they will be replaced by macro functions
|
||||
*/
|
||||
|
||||
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);
|
||||
/*
|
||||
Retrieve the value of the widget. Options are:
|
||||
asString: Optionally return the value as a string
|
||||
*/
|
||||
ViewWidget.prototype.getValue = function(options) {
|
||||
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 {
|
||||
let tiddler;
|
||||
if(this.viewSubtiddler) {
|
||||
tiddler = this.wiki.getSubTiddler(this.viewTitle, this.viewSubtiddler);
|
||||
tiddler = this.wiki.getTiddler(this.viewTitle);
|
||||
}
|
||||
if(tiddler) {
|
||||
if(this.viewField === "text" && !this.viewSubtiddler) {
|
||||
// Calling getTiddlerText() triggers lazy loading of skinny tiddlers
|
||||
value = this.wiki.getTiddlerText(this.viewTitle);
|
||||
} 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];
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(this.viewField === "title") {
|
||||
value = this.viewTitle;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
getValueAsText() {
|
||||
return this.getValue({asString: true});
|
||||
ViewWidget.prototype.getValueAsText = function() {
|
||||
return this.getValue({asString: true});
|
||||
};
|
||||
|
||||
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 "";
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
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");
|
||||
};
|
||||
|
||||
exports.view = ViewWidget;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
exports.view = ViewWidget;
|
||||
|
||||
@@ -369,31 +369,16 @@ Sort an array of tiddler titles by a specified field
|
||||
isDescending: true if the sort should be descending
|
||||
isCaseSensitive: true if the sort should consider upper and lower case letters to be different
|
||||
*/
|
||||
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric) {
|
||||
exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,isNumeric,isAlphaNumeric,locale) {
|
||||
var self = this;
|
||||
if(sortField === "title") {
|
||||
if(!isNumeric && !isAlphaNumeric) {
|
||||
if(isCaseSensitive) {
|
||||
if(isDescending) {
|
||||
titles.sort(function(a,b) {
|
||||
return b.localeCompare(a);
|
||||
});
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
}
|
||||
const sorter = new Intl.Collator(locale, { sensitivity: isCaseSensitive ? "variant" : "accent" });
|
||||
if(isDescending) {
|
||||
titles.sort((a,b) => sorter.compare(b, a));
|
||||
} else {
|
||||
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());
|
||||
});
|
||||
}
|
||||
}
|
||||
titles.sort((a,b) => sorter.compare(a, b));
|
||||
}
|
||||
} else {
|
||||
titles.sort(function(a,b) {
|
||||
var x,y;
|
||||
@@ -414,14 +399,8 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isAlphaNumeric) {
|
||||
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);
|
||||
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" });
|
||||
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -463,14 +442,8 @@ exports.sortTiddlers = function(titles,sortField,isDescending,isCaseSensitive,is
|
||||
}
|
||||
a = String(a);
|
||||
b = String(b);
|
||||
if(isAlphaNumeric) {
|
||||
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);
|
||||
const sorter = new Intl.Collator(locale, { numeric: isAlphaNumeric, sensitivity: isAlphaNumeric ? "base" : isCaseSensitive ? "variant" : "accent" });
|
||||
return isDescending ? sorter.compare(b, a) : sorter.compare(a, b);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,7 +25,6 @@ title: $:/core/templates/tiddlywiki5.html
|
||||
`{{{ [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/RawMarkupWikified]] ||$:/core/templates/raw-static-tiddler}}}`
|
||||
<!--~~ Style section start ~~-->
|
||||
</head>
|
||||
<body class="tc-body">
|
||||
<!--~~ Raw markup for the top of the body section ~~-->
|
||||
|
||||
@@ -96,13 +96,24 @@ caption: {{$:/language/Search/Filter/Caption}}
|
||||
</$list>
|
||||
</div>
|
||||
|
||||
<div class="tc-advanced-search-options">
|
||||
<$checkbox tiddler="$:/config/Search/AllowDuplicates" field="text" checked="yes" unchecked="no" default="yes">
|
||||
<$text text=" "/><<lingo Filter/AllowDuplicates>>
|
||||
</$checkbox>
|
||||
</div>
|
||||
|
||||
<$reveal state="$:/temp/advancedsearch" type="nomatch" text="" tag="div" class="tc-search-results">
|
||||
<$set name="resultCount" value="<$count filter={{$:/temp/advancedsearch}}/>">
|
||||
<$let
|
||||
filter-allow-duplicates="::defaultprefix:all [subfilter{$:/temp/advancedsearch}]"
|
||||
filter-deduplicate="::defaultprefix:or [subfilter{$:/temp/advancedsearch}]"
|
||||
currentFilter={{{ [{$:/config/Search/AllowDuplicates}match[yes]then<filter-allow-duplicates>else<filter-deduplicate>] }}}
|
||||
resultCount={{{ [subfilter<currentFilter>count[]] }}}
|
||||
>
|
||||
<p><<lingo Filter/Matches>></p>
|
||||
<$list filter={{$:/temp/advancedsearch}}>
|
||||
<$list filter="[subfilter<currentFilter>]">
|
||||
<span class={{{[<currentTiddler>addsuffix[-primaryList]] -[[$:/temp/advancedsearch/selected-item]get[text]] :and[then[]else[tc-list-item-selected]] }}}>
|
||||
<$transclude tiddler="$:/core/ui/ListItemTemplate"/>
|
||||
</span>
|
||||
</$list>
|
||||
</$set>
|
||||
</$let>
|
||||
</$reveal>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
title: $:/core/ui/PageTemplate/alerts
|
||||
tags: $:/tags/PageTemplate
|
||||
|
||||
<div class="tc-alerts" role="region" aria-label="Alerts">
|
||||
<div class="tc-alerts" role="region" aria-label={{$:/language/Alerts}}>
|
||||
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/Alert]!is[draft]]" template="$:/core/ui/AlertTemplate" storyview="pop"/>
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
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>
|
||||
@@ -2,7 +2,7 @@ title: $:/core/ui/TiddlerInfo
|
||||
|
||||
\whitespace trim
|
||||
<div style="position:relative;">
|
||||
<div class="tc-tiddler-controls" style="position:absolute;right:0;">
|
||||
<div class="tc-tiddler-controls tc-tiddler-info-controls">
|
||||
<$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">
|
||||
{{$:/core/images/close-button}}
|
||||
|
||||
@@ -11,9 +11,13 @@ tags: $:/tags/ViewTemplate
|
||||
storyview="pop"
|
||||
variable="listItem"
|
||||
>
|
||||
<$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]">
|
||||
<$transclude tiddler=<<listItem>>/>
|
||||
</$set>
|
||||
<$let condition={{{ [<listItem>get[condition]] }}}>
|
||||
<%if [<condition>!is[blank]] :and[<currentTiddler>subfilter<condition>limit[1]] :else[<condition>is[blank]then[true]] %>
|
||||
<$set name="tv-config-toolbar-class" filter="[<tv-config-toolbar-class>] [<listItem>encodeuricomponent[]addprefix[tc-btn-]]">
|
||||
<$transclude tiddler=<<listItem>>/>
|
||||
</$set>
|
||||
<%endif%>
|
||||
</$let>
|
||||
</$list>
|
||||
</span>
|
||||
<$set name="tv-wikilinks" value={{$:/config/Tiddlers/TitleLinks}}>
|
||||
|
||||
@@ -41,6 +41,8 @@ Drag this link to copy this tool to another wiki
|
||||
</$wikify>
|
||||
\end capture-item-wikified
|
||||
|
||||
\function get.shadow.source() [shadowsource[]]
|
||||
|
||||
\procedure capture-wiki-info(tempWikiInfo)
|
||||
<$transclude $variable="capture-item-wikified" label="TiddlyWiki Version" value="<<version>>"/>
|
||||
<$transclude $variable="capture-item" label="Current palette" value={{$:/palette}}/>
|
||||
@@ -64,6 +66,7 @@ Drag this link to copy this tool to another wiki
|
||||
<$transclude $variable="capture-item" label="Keyboard shortcuts that have been customised" value={{{ [all[tiddlers]prefix[$:/config/shortcuts]] +[join[,]] }}}/>
|
||||
<$transclude $variable="capture-item" label="Disabled plugins" value={{{ [all[tiddlers]prefix[$:/config/Plugins/Disabled/]] :filter[{!!text}match[yes]] :map[<currentTiddler>removeprefix[$:/config/Plugins/Disabled/]] +[join[,]] }}}/>
|
||||
<$transclude $variable="capture-item" label="Plugins" value={{{ [has[plugin-type]sort[]] :filter[<currentTiddler>addprefix[$:/config/Plugins/Disabled/]get[text]else[no]!match[yes]] :map[{!!version}addprefix[ - ]addprefix<currentTiddler>] +[addprefix[ ]addprefix<crlf>join[]] }}}/>
|
||||
<$transclude $variable="capture-item" label="Stylesheets" value={{{ [all[shadows+tiddlers]tag[$:/tags/Stylesheet]!is[draft]] :map[is[shadow]addsuffix[ ∈ ]addsuffix<get.shadow.source>else<currentTiddler>] +[addprefix[ ]addprefix<crlf>join[]] }}}/>
|
||||
\end capture-wiki-info
|
||||
|
||||
\procedure template-header()
|
||||
|
||||
2
core/wiki/config/SearchAllowDuplicates.tid
Normal file
2
core/wiki/config/SearchAllowDuplicates.tid
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/config/Search/AllowDuplicates
|
||||
text: yes
|
||||
39
core/wiki/macros/CSS-property.tid
Normal file
39
core/wiki/macros/CSS-property.tid
Normal file
@@ -0,0 +1,39 @@
|
||||
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
|
||||
@@ -22,7 +22,7 @@ tags: $:/tags/Macro
|
||||
<$action-listops $tiddler=<<targetTiddler>> $field=<<targetField>> $subfilter="+[insertbefore<actionTiddler>,<currentTiddler>]"/>
|
||||
\end
|
||||
|
||||
\define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate)
|
||||
\define list-links-draggable(tiddler,field:"list",emptyMessage,type:"ul",subtype:"li",class:"",itemTemplate, displayField:"caption")
|
||||
\whitespace trim
|
||||
<$set name="_tiddler" value="""$tiddler$""" emptyValue=<<currentTiddler>> >
|
||||
<$let field-reference={{{ [<_tiddler>] "!!" [[$field$]] +[join[]] }}}
|
||||
@@ -42,7 +42,7 @@ tags: $:/tags/Macro
|
||||
<$transclude tiddler="""$itemTemplate$""">
|
||||
<$link to={{!!title}}>
|
||||
<$let tv-wikilinks="no">
|
||||
<$transclude field="caption">
|
||||
<$transclude field=<<__displayField__>>>
|
||||
<$view field="title"/>
|
||||
</$transclude>
|
||||
</$let>
|
||||
@@ -92,7 +92,7 @@ tags: $:/tags/Macro
|
||||
</$set>
|
||||
\end
|
||||
|
||||
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"")
|
||||
\define list-tagged-draggable(tag,subFilter,emptyMessage,itemTemplate,elementTag:"div",storyview:"",displayField:"caption")
|
||||
\whitespace trim
|
||||
<span class="tc-tagged-draggable-list">
|
||||
<$set name="tag" value=<<__tag__>>>
|
||||
@@ -110,6 +110,11 @@ tags: $:/tags/Macro
|
||||
<$genesis $type=<<__elementTag__>>>
|
||||
<$transclude tiddler="""$itemTemplate$""">
|
||||
<$link to={{!!title}}>
|
||||
<$let tv-wikilinks="no">
|
||||
<$transclude field=<<__displayField__>>>
|
||||
<$view field="title"/>
|
||||
</$transclude>
|
||||
</$let>
|
||||
<$view field="title"/>
|
||||
</$link>
|
||||
</$transclude>
|
||||
|
||||
@@ -9,8 +9,9 @@ code-body: yes
|
||||
setTo=<<currentTab>>
|
||||
default=<<__default__>>
|
||||
selectedClass="tc-tab-selected"
|
||||
selectedAria="aria-selected"
|
||||
tooltip={{!!tooltip}}
|
||||
role="switch"
|
||||
role="tab"
|
||||
data-tab-title=<<currentTab>>
|
||||
>
|
||||
<$tiddler tiddler=<<save-currentTiddler>>>
|
||||
@@ -57,12 +58,12 @@ code-body: yes
|
||||
\whitespace trim
|
||||
<$qualify title=<<__state__>> name="qualifiedState">
|
||||
<$let tabsState={{{ [<__explicitState__>minlength[1]] ~[<qualifiedState>] }}}>
|
||||
<div class={{{ [[tc-tab-set]addsuffix[ ]addsuffix<__class__>] }}}>
|
||||
<div class={{{ [[tc-tab-set]addsuffix[ ]addsuffix<__class__>] }}} role="tablist">
|
||||
<div class={{{ [[tc-tab-buttons]addsuffix[ ]addsuffix<__class__>] }}}>
|
||||
<<tabs-tab-list>>
|
||||
</div>
|
||||
<div class={{{ [[tc-tab-divider]addsuffix[ ]addsuffix<__class__>] }}}/>
|
||||
<div class={{{ [[tc-tab-content]addsuffix[ ]addsuffix<__class__>] }}}>
|
||||
<div class={{{ [[tc-tab-content]addsuffix[ ]addsuffix<__class__>] }}} role="tabpanel">
|
||||
<<tabs-tab-body>>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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
|
||||
@@ -0,0 +1,17 @@
|
||||
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}}
|
||||
@@ -1,18 +0,0 @@
|
||||
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
|
||||
@@ -0,0 +1,18 @@
|
||||
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}}
|
||||
@@ -0,0 +1,21 @@
|
||||
title: Filters/DefaultFilterRunPrefixPragma
|
||||
description: Test Default Filter Run Prefix Pragma
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure mysubfilter() 1 1 +[join[Y]]
|
||||
|
||||
(<$text text={{{ ::defaultprefix:all 1 1 [subfilter<mysubfilter>] +[join[X]] }}}/>)
|
||||
|
||||
(<$text text={{{ 1 1 ::defaultprefix:all 1 1 +[join[X]] }}}/>)
|
||||
|
||||
(<$text text={{{ ::nonexistent X }}}/>)
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>(1X1X1Y1)</p><p>(1X1X1)</p><p>(Filter Error: Unknown filter pragma)</p>
|
||||
22
editions/test/tiddlers/tests/data/filters/Filter.tid
Normal file
22
editions/test/tiddlers/tests/data/filters/Filter.tid
Normal file
@@ -0,0 +1,22 @@
|
||||
title: Filters/Filter
|
||||
description: Test filter operator
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test-filter() 1 1 +[join[X]] +[!match<currentTiddler>]
|
||||
|
||||
(<$text text={{{ [filter<test-filter>] +[join[ ]] }}}/>)
|
||||
|
||||
(<$text text={{{ [filter:all<test-filter>] +[join[ ]] }}}/>)
|
||||
|
||||
+
|
||||
title: 1X1
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>($:/core 1X1 ExpectedResult Output)</p><p>($:/core ExpectedResult Output)</p>
|
||||
20
editions/test/tiddlers/tests/data/filters/Subfilter.tid
Normal file
20
editions/test/tiddlers/tests/data/filters/Subfilter.tid
Normal file
@@ -0,0 +1,20 @@
|
||||
title: Filters/Subfilter
|
||||
description: Test subfilter operator
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
|
||||
\procedure test-data() 1 2 1 3 3 4
|
||||
|
||||
(<$text text={{{ [subfilter<test-data>] +[join[ ]] }}}/>)
|
||||
|
||||
(<$text text={{{ [subfilter:all<test-data>] +[join[ ]] }}}/>)
|
||||
|
||||
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p>(2 1 3 4)</p><p>(1 2 1 3 3 4)</p>
|
||||
@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-a
|
||||
type: text/html
|
||||
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 "><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>
|
||||
<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>
|
||||
|
||||
@@ -2,4 +2,4 @@ title: expected-test-tabs-horizontal-all
|
||||
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
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -2,4 +2,4 @@ title: expected-test-tabs-vertical
|
||||
type: text/html
|
||||
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"><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>
|
||||
<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>
|
||||
|
||||
6
editions/tw5.com/tiddlers/Locale Example.tid
Normal file
6
editions/tw5.com/tiddlers/Locale Example.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
created: 20251001034405510
|
||||
list: A a Ä ä Z z O o Õ õ Ö ö Ü ü Y y
|
||||
modified: 20251218023544134
|
||||
tags:
|
||||
title: Locale Example
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -26,7 +26,6 @@ For the convenience of existing users, we also continue to operate the original
|
||||
|
||||
* [[TiddlyWiki Subreddit|https://www.reddit.com/r/TiddlyWiki5/]]
|
||||
* Chat on Discord at https://discord.gg/HFFZVQ8
|
||||
* [[TiddlyWiki Subreddit|https://www.reddit.com/r/TiddlyWiki5/]]
|
||||
|
||||
!! Developers
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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
|
||||
@@ -0,0 +1,16 @@
|
||||
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}}
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150117190213631
|
||||
modified: 20230226144641763
|
||||
modified: 20251225215015507
|
||||
tags: Concepts
|
||||
title: Date Fields
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -28,4 +28,5 @@ As an example, the <<.field created>> field of this tiddler has the value <<.val
|
||||
Dates can be [[converted to other formats|DateFormat]] for display:
|
||||
|
||||
<$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"/>"""/>
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ tags: Filters
|
||||
title: Dominant Append
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Description and link to new escape hatches
|
||||
|
||||
[[Filters]] manipulate [[sets of titles|Title Selection]] in which no title may appear more than once. Furthermore, they often need to append one such set to another.
|
||||
|
||||
This is done in such a way that, if a title would be duplicated, the earlier copy of that title is discarded. The titles being appended are dominant.
|
||||
|
||||
@@ -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.
|
||||
* [[Filtered Transclusions|Transclusion in WikiText]] -- if you want to use filter results in your text
|
||||
* [[TiddlyWiki Syntax History]] -- if you are curious why the filter syntax is the way it is
|
||||
* [[Filter Syntax History]] -- if you are curious why the filter syntax is the way it is
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
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]].
|
||||
@@ -1,7 +1,9 @@
|
||||
created: 20211117003509226
|
||||
modified: 20251119135921343
|
||||
modified: 20260102135713260
|
||||
tags: sampletag1 sampletag2 [[Widget Examples]]
|
||||
title: SampleTiddlerFirst
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
This is a test tiddler called SampleTidlerFirst.
|
||||
This is a test tiddler called SampleTidlerFirst.
|
||||
It is used in [[DiffTextWidget]].
|
||||
You can modify its content.
|
||||
@@ -1,6 +1,8 @@
|
||||
created: 20211117003511221
|
||||
modified: 20211117003724108
|
||||
modified: 20260102135739735
|
||||
tags: sampletag1 sampletag2 [[Widget Examples]]
|
||||
title: SampleTiddlerSecond
|
||||
|
||||
This test tiddler is called SampleTiddlerSecond.
|
||||
This test tiddler is called SampleTiddlerSecond.
|
||||
It is used in [[DiffTextWidget]].
|
||||
You can edit its content.
|
||||
@@ -8,7 +8,7 @@ op-output: the titles stored as a [[title list|Title List]] at <<.place L>>
|
||||
op-parameter: a [[title list|Title List]]
|
||||
op-parameter-name: L
|
||||
op-purpose: select titles from the parameter interpreted as a [[title list|Title List]]
|
||||
op-suffix: <<.from-version "5.1.20">> `dedupe` (the default) to remove duplicates, `raw` to leave duplicates untouched
|
||||
op-suffix: <<.from-version "5.1.20">> `dedupe` (the default) to remove duplicates, `all` (or `raw`) to leave duplicates untouched
|
||||
op-suffix-name: D
|
||||
tags: [[Filter Operators]] [[Field Operators]] [[Selection Constructors]] [[Negatable Operators]]
|
||||
title: enlist Operator
|
||||
|
||||
@@ -4,7 +4,7 @@ modified: 20201102221854719
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the titles stored as a [[title list|Title List]] in each input title
|
||||
op-purpose: select titles by interpreting each input title as a [[title list|Title List]]
|
||||
op-suffix: `dedupe` (the default) to remove duplicates, `raw` to leave duplicates untouched
|
||||
op-suffix: `dedupe` (the default) to remove duplicates, `all` (or `raw`) to leave duplicates untouched
|
||||
op-suffix-name: D
|
||||
tags: [[Filter Operators]] [[String Operators]]
|
||||
title: enlist-input Operator
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150124112340000
|
||||
modified: 20150124113250000
|
||||
modified: 20251218023608468
|
||||
tags: [[sort Operator]] [[Operator Examples]]
|
||||
title: sort Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -11,3 +11,10 @@ type: text/vnd.tiddlywiki
|
||||
<<.operator-example 3 "one two Three four +[sort[]]">>
|
||||
<<.operator-example 4 "[prefix[Tiddl]sort[text]]">>
|
||||
<<.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]]">>
|
||||
|
||||
@@ -12,6 +12,8 @@ tags: [[Filter Operators]] [[Negatable Operators]]
|
||||
title: filter Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Description of new parameter
|
||||
|
||||
<<.from-version "5.1.23">> The <<.op filter>> operator runs a subfilter for each input title, and returns those input titles for which the subfilter returns a non-empty result (in other words the result is not an empty list). The results of the subfilter are thrown away.
|
||||
|
||||
Simple filter operations can be concatenated together directly (eg `[tag[HelloThere]search[po]]`) but this doesn't work when the filtering operations require intermediate results to be computed. The <<.op filter>> operator can be used to filter on an intermediate result which is discarded. To take the same example but to also filter by those tiddlers whose text field is longer than 1000 characters:
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
caption: nsort
|
||||
created: 20140410103123179
|
||||
modified: 20150203190051000
|
||||
modified: 20251227084602319
|
||||
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]]
|
||||
title: nsort Operator
|
||||
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>>.
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
caption: nsortcs
|
||||
created: 20140410103123179
|
||||
modified: 20150417125717078
|
||||
modified: 20251227084615705
|
||||
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 <<.place F>>, treating field values as numbers
|
||||
op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
|
||||
op-parameter: accept same parameters as the [[sort Operator]]
|
||||
op-parameter-name: F
|
||||
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]]
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
caption: sort
|
||||
created: 20140410103123179
|
||||
modified: 20150203191228000
|
||||
modified: 20251227084644651
|
||||
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]]
|
||||
title: sort Operator
|
||||
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>>.
|
||||
|
||||
```
|
||||
[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">>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
caption: sortan
|
||||
created: 20180222071605739
|
||||
modified: 20180223012553446
|
||||
modified: 20251227084439804
|
||||
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 alphanumerics
|
||||
op-parameter: the name of a [[field|TiddlerFields]], defaulting to <<.field title>>
|
||||
op-parameter: accept same parameters as the [[sort Operator]]
|
||||
op-parameter-name: F
|
||||
op-purpose: sort the input by text field considering them as alphanumerics
|
||||
tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
caption: sortcs
|
||||
created: 20140410103123179
|
||||
modified: 20150417125704503
|
||||
modified: 20251227084416522
|
||||
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 name of a [[field|TiddlerFields]], defaulting to <<.field title>>
|
||||
op-parameter: accept same parameters as the [[sort Operator]]
|
||||
op-parameter-name: F
|
||||
op-purpose: sort the input by text field, treating upper and lower case as different
|
||||
tags: [[Filter Operators]] [[Field Operators]] [[Order Operators]] [[Negatable Operators]]
|
||||
|
||||
@@ -12,6 +12,8 @@ tags: [[Filter Operators]] [[Field Operators]] [[Selection Constructors]] [[Nega
|
||||
title: subfilter Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Description of new parameter
|
||||
|
||||
<<.from-version "5.1.18">> Note that the <<.op subfilter>> operator was introduced in version 5.1.18 and is not available in earlier versions.
|
||||
|
||||
<<.tip " Literal filter parameters cannot contain square brackets but you can work around the issue by using a variable:">>
|
||||
|
||||
@@ -4,6 +4,8 @@ tags: [[Filter Syntax]]
|
||||
title: Filter Expression
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Update railroad diagram
|
||||
|
||||
A <<.def "filter expression">> is the outermost level of the [[filter syntax|Filter Syntax]]. It consists of [[filter runs|Filter Run]] with optional [[filter run prefixes|Filter Run Prefix]]. Multiple filter runs are separated by [[whitespace|Filter Whitespace]].
|
||||
|
||||
<$railroad text="""
|
||||
|
||||
11
editions/tw5.com/tiddlers/filters/syntax/Filter Pragma.tid
Normal file
11
editions/tw5.com/tiddlers/filters/syntax/Filter Pragma.tid
Normal file
@@ -0,0 +1,11 @@
|
||||
created: 20260122212128206
|
||||
modified: 20260122212128206
|
||||
tags: [[Filter Expression]]
|
||||
title: Filter Pragma
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: High level pragma docs & railroad diagram
|
||||
|
||||
A <<.def "filter pragma">> is a special instruction embedded within a filter expression that affects the behavior of subsequent filter operations. Filter pragmas are similar to wikitext pragmas and are used to control aspects of filter evaluation. They do not appear at the start of a filter, but can be placed between other filter runs.
|
||||
|
||||
The `::defaultprefix` pragma sets the default filter run prefix for the remainder of the filter expression. This allows users to control deduplication behavior without having to specify prefixes for each individual operation.
|
||||
@@ -4,6 +4,8 @@ tags: [[Filter Expression]]
|
||||
title: Filter Run Prefix
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Link to how the default filter run prefix can be specified
|
||||
|
||||
There are 2 types of filter run prefixes that are interchangeable; [[named prefixes|Named Filter Run Prefix]] and [[shortcut prefixes|Shortcut Filter Run Prefix]].
|
||||
|
||||
<$railroad text="""
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
created: 20260122212128206
|
||||
modified: 20260122212128206
|
||||
tags: [[Filter Pragma]]
|
||||
title: defaultprefix Filter Pragma
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
TODO:docs-default-prefix-for-subfilter: Purpose and docs of new pragma
|
||||
|
||||
A <<.def "defaultprefix filter pragma">> is used to set the default [[Filter Run Prefix]] for the remainder of the filter expression. This allows users to control deduplication behavior without having to specify prefixes for each individual operation.
|
||||
|
||||
Any of the [[named prefixes|Named Filter Run Prefix]] can be specified as the default prefix, but `all` is the most commonly used value to disable deduplication.
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
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.
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150414070451144
|
||||
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]]
|
||||
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]]
|
||||
modified: 20150414070948246
|
||||
title: HelloThumbnail
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
@@ -5,5 +5,6 @@ link: TiddlyWiki Newsletter
|
||||
image: TiddlyWiki Newsletter Badge
|
||||
color: #fff
|
||||
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
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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
|
||||
@@ -31,6 +31,10 @@ The <<.def list-links-draggable>> [[macro|Macros]] renders the ListField of a ti
|
||||
; itemTemplate
|
||||
: 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.
|
||||
|
||||
<<.macro-examples "list-links-draggable">>
|
||||
|
||||
@@ -17,6 +17,9 @@ 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
|
||||
;emptyMessage
|
||||
: Optional wikitext to display if there are no tiddlers with the specified tag
|
||||
Here’s 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.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
caption: tag-pill
|
||||
created: 20161128190930538
|
||||
modified: 20161128191220364
|
||||
modified: 20260114112210310
|
||||
tags: Macros [[Core Macros]]
|
||||
title: tag-pill Macro
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -9,13 +9,18 @@ The <<.def tag-pill>> [[macro|Macros]] generates a static tag pill showing a spe
|
||||
|
||||
!! Parameters
|
||||
|
||||
;tag
|
||||
; tag
|
||||
: The title of the tag
|
||||
;element-tag
|
||||
: The element name to be used for the pill (defaults to "span")
|
||||
;element-attributes
|
||||
: Additional attributes for the pill element
|
||||
;actions
|
||||
: Action widgets to be triggered when the pill is clicked. Within the text, the macro parameter ''tag'' contains the title of the selected tag.
|
||||
|
||||
; element-tag
|
||||
: The element name to be used for the pill (defaults to HTML element SPAN).
|
||||
: If an ''actions'' parameter is used the element-tag needs to be set to `$button`
|
||||
|
||||
; element-attributes
|
||||
: Additional attributes for the element specified in ''element-tag''
|
||||
|
||||
; actions
|
||||
: If an actions parameter should be activated, the ''element-tag'' parameter needs to be set to `$button`.
|
||||
: Action widgets to be triggered when the pill is clicked. Within the text, the macro parameter ''tag'' contains the title of the selected tag
|
||||
|
||||
<<.macro-examples "tag-pill">>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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.
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9148.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9148.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
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.
|
||||
12
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9177.tid
Normal file
12
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9177.tid
Normal file
@@ -0,0 +1,12 @@
|
||||
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.
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9348.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9348.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
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.
|
||||
@@ -0,0 +1,9 @@
|
||||
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
|
||||
|
||||
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9400.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9400.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
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.
|
||||
15
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9466.tid
Normal file
15
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9466.tid
Normal file
@@ -0,0 +1,15 @@
|
||||
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]]
|
||||
```
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9538.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9538.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
title: $:/changenotes/5.4.0/#9538
|
||||
description: Fix browser storage plugin making wiki dirty
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: bugfix
|
||||
change-category: plugin
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9538
|
||||
github-contributors: Jermolene
|
||||
|
||||
Fixed issue where the browser storage plugin caused the wiki to be marked as dirty every time it starts up. The problem was due to the use of a log tiddler titled `$:/info/browser/storage/persisted`, the fix is to rename it to `$:/state/browser/storage/persisted`.
|
||||
15
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9551.tid
Normal file
15
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9551.tid
Normal file
@@ -0,0 +1,15 @@
|
||||
title: $:/changenotes/5.4.0/#9551
|
||||
description: Add words and lines modes to diff-text widget
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: widget
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9551
|
||||
github-contributors: yaisog
|
||||
|
||||
The DiffTextWidget now supports two additional diff modes via the `mode` attribute:
|
||||
|
||||
* `mode="words"` - Performs word-level diff operations, making differences more intelligible when comparing text
|
||||
* `mode="lines"` - Performs line-level diff operations, highlighting entire lines that have changed
|
||||
|
||||
The default `mode="chars"` continues to work as before, performing character-level diff operations.
|
||||
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9570.tid
Normal file
10
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9570.tid
Normal file
@@ -0,0 +1,10 @@
|
||||
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`.
|
||||
34
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9595.tid
Normal file
34
editions/tw5.com/tiddlers/releasenotes/5.4.0/#9595.tid
Normal file
@@ -0,0 +1,34 @@
|
||||
title: $:/changenotes/5.4.0/#9595
|
||||
description: Easier avoidance of deduplication in filters
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: filters
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9595
|
||||
github-contributors: Jermolene
|
||||
|
||||
Resolves a long-standing issue with filters where there has been no easy way to avoid deduplication of results during filter evaluation. There are two distinct new capabilities.
|
||||
|
||||
First, there is a new filter pragma `::defaultprefix` that sets the default filter run prefix for the remainder of the filter expression. Filter pragmas are a new concept akin to wikitext pragmas, allowing special instructions to be embedded in filter expressions.
|
||||
|
||||
The `::defaultprefix` pragma takes as its first parameter the desired default filter run prefix, followed by any number of filter operations to which it applies. The default prefix `all` can be used to disable deduplication for the subsequent operations (`or` is the default prefix that performs deduplication).
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
::defaultprefix:all 1 2 2 1 4 +[join[ ]]
|
||||
```
|
||||
|
||||
Returns `1 2 2 1 4`.
|
||||
|
||||
Contrast to the result without the pragma which returns `2 1 4`:
|
||||
|
||||
```
|
||||
1 2 2 1 4 +[join[ ]]
|
||||
```
|
||||
|
||||
Second, there is a new parameter to the `subfilter` and `filter` operators to specify the default filter run prefix to use when the filter is evaluated. This overrides any default set with the `::defaultprefix` pragma.
|
||||
|
||||
```
|
||||
[subfilter:all<my-subfilter>]
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
title: $:/changenotes/5.4.0/#9565
|
||||
description: Add stylesheet wiki information
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: feature
|
||||
change-category: internal
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9565
|
||||
github-contributors: Leilei332
|
||||
|
||||
Extend wiki information tool to display stylesheet information.
|
||||
@@ -0,0 +1,18 @@
|
||||
title: $:/changenotes/5.4.0/#9513
|
||||
description: Bump markdown-it and its plugins to newest version
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: plugin
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9513
|
||||
github-contributors: Leilei332
|
||||
|
||||
Upgrade the markdown-it libraries used by the [[Markdown Plugin]]:
|
||||
|
||||
* markdown-it: 14.1.0
|
||||
* markdown-it-deflist: 3.0.0
|
||||
* markdown-it-footnote: 4.0.0
|
||||
* markdown-it-ins: 4.0.0
|
||||
* markdown-it-mark: 4.0.0
|
||||
* markdown-it-sub: 2.0.0
|
||||
* markdown-it-sup: 2.0.0
|
||||
@@ -0,0 +1,10 @@
|
||||
title: $:/changenotes/5.4.0/#9248
|
||||
description: Improve alert accessibility
|
||||
release: 5.4.0
|
||||
tags: $:/tags/ChangeNote
|
||||
change-type: enhancement
|
||||
change-category: usability
|
||||
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9248 https://github.com/TiddlyWiki/TiddlyWiki5/pull/9575
|
||||
github-contributors: Leilei332
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
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
|
||||
@@ -0,0 +1,10 @@
|
||||
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]].
|
||||
@@ -0,0 +1,14 @@
|
||||
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`
|
||||
@@ -4,7 +4,7 @@ created: 20160216191710789
|
||||
delivery: Protocol
|
||||
description: Standard web protocol available on products such as Sharepoint
|
||||
method: save
|
||||
modified: 20220615155048712
|
||||
modified: 20260102081028704
|
||||
tags: Android Chrome Firefox [[Internet Explorer]] Linux Mac Opera PHP Safari Saving Windows iOS Edge
|
||||
title: Saving via WebDAV
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -19,6 +19,9 @@ Lightweight, portable and easy to use solutions
|
||||
|
||||
* [[rclone|https://rclone.org/commands/rclone_serve_webdav/]]
|
||||
** 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]]
|
||||
* [[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/]]
|
||||
@@ -44,6 +47,10 @@ 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.
|
||||
|
||||
!! 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
|
||||
|
||||
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:
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user