mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-23 03:14:40 +00:00
Compare commits
20 Commits
direct-sty
...
fix-6382
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dcfc3ad2e | ||
|
|
6a9cc87255 | ||
|
|
ab3109d84b | ||
|
|
a4ab42da8a | ||
|
|
af87727ffc | ||
|
|
6b4e5c74ad | ||
|
|
8af99878cc | ||
|
|
d6d2bc455c | ||
|
|
d5ff723d4c | ||
|
|
1d0af90ba2 | ||
|
|
59572cd75d | ||
|
|
1e4f444b63 | ||
|
|
b6831ed35d | ||
|
|
762de81444 | ||
|
|
ca9f320886 | ||
|
|
d8c3d18a00 | ||
|
|
ee03ee57f5 | ||
|
|
13d1f6d6c1 | ||
|
|
51175616d3 | ||
|
|
32f79d16c6 |
28
boot/boot.js
28
boot/boot.js
@@ -68,6 +68,26 @@ $tw.utils.isArrayEqual = function(array1,array2) {
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Add an entry to a sorted array if it doesn't already exist, while maintaining the sort order
|
||||
*/
|
||||
$tw.utils.insertSortedArray = function(array,value) {
|
||||
var low = 0, high = array.length - 1, mid, cmp;
|
||||
while(low <= high) {
|
||||
mid = (low + high) >> 1;
|
||||
cmp = value.localeCompare(array[mid]);
|
||||
if(cmp > 0) {
|
||||
low = mid + 1;
|
||||
} else if(cmp < 0) {
|
||||
high = mid - 1;
|
||||
} else {
|
||||
return array;
|
||||
}
|
||||
}
|
||||
array.splice(low,0,value);
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
Push entries onto an array, removing them first if they already exist in the array
|
||||
array: array to modify (assumed to be free of duplicates)
|
||||
@@ -1081,7 +1101,7 @@ $tw.Wiki = function(options) {
|
||||
tiddlerTitles = null, // Array of tiddler titles
|
||||
getTiddlerTitles = function() {
|
||||
if(!tiddlerTitles) {
|
||||
tiddlerTitles = Object.keys(tiddlers);
|
||||
tiddlerTitles = Object.keys(tiddlers).sort(function(a,b) {return a.localeCompare(b);});
|
||||
}
|
||||
return tiddlerTitles;
|
||||
},
|
||||
@@ -1134,10 +1154,8 @@ $tw.Wiki = function(options) {
|
||||
}
|
||||
// Save the new tiddler
|
||||
tiddlers[title] = tiddler;
|
||||
// Check we've got it's title
|
||||
if(tiddlerTitles && tiddlerTitles.indexOf(title) === -1) {
|
||||
tiddlerTitles.push(title);
|
||||
}
|
||||
// Check we've got the title
|
||||
tiddlerTitles = $tw.utils.insertSortedArray(tiddlerTitles || [],title);
|
||||
// Record the new tiddler state
|
||||
updateDescriptor["new"] = {
|
||||
tiddler: tiddler,
|
||||
|
||||
@@ -5,9 +5,11 @@ module-type: filteroperator
|
||||
|
||||
Filter operator that looks up values via a title prefix
|
||||
|
||||
[lookup:<field>[<prefix>]]
|
||||
[lookup:<defaultvalue>:<field OR index>[<prefix>],[<field-name OR index-name>]]
|
||||
|
||||
Prepends the prefix to the selected items and returns the specified field value
|
||||
Prepends the prefix to the selected items and returns the specified
|
||||
field or index value. If the 2nd suffix does not exist, it defaults to field.
|
||||
If the second operand is missing it defaults to "text" for fields, and "0" for indexes
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
@@ -20,10 +22,31 @@ Prepends the prefix to the selected items and returns the specified field value
|
||||
Export our filter function
|
||||
*/
|
||||
exports.lookup = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
results.push(options.wiki.getTiddlerText(operator.operand + title) || operator.suffix || '');
|
||||
});
|
||||
var results = [],
|
||||
suffixes = operator.suffixes || [],
|
||||
defaultSuffix = suffixes[0] ? (suffixes[0][0] || "") : "",
|
||||
indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false,
|
||||
target;
|
||||
if(operator.operands.length == 2) {
|
||||
target = operator.operands[1]
|
||||
} else {
|
||||
target = indexSuffix ? "0": "text";
|
||||
}
|
||||
if(indexSuffix) {
|
||||
source(function(tiddler,title) {
|
||||
var data = options.wiki.extractTiddlerDataItem(operator.operands[0]+title,target,defaultSuffix);
|
||||
results.push(data);
|
||||
});
|
||||
} else {
|
||||
source(function(tiddler,title) {
|
||||
var value = defaultSuffix;
|
||||
var targetTiddler = options.wiki.getTiddler(operator.operands[0]+title);
|
||||
if(targetTiddler && targetTiddler.getFieldString(target)) {
|
||||
value = targetTiddler.getFieldString(target);
|
||||
}
|
||||
results.push(value);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ exports.search = function(source,operator,options) {
|
||||
invert: invert,
|
||||
field: fields,
|
||||
excludeField: excludeFields,
|
||||
some: hasFlag("some"),
|
||||
caseSensitive: hasFlag("casesensitive"),
|
||||
literal: hasFlag("literal"),
|
||||
whitespace: hasFlag("whitespace"),
|
||||
|
||||
@@ -34,7 +34,6 @@ function Server(options) {
|
||||
this.authenticators = options.authenticators || [];
|
||||
this.wiki = options.wiki;
|
||||
this.boot = options.boot || $tw.boot;
|
||||
this.servername = $tw.utils.transliterateToSafeASCII(this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
||||
// Initialise the variables
|
||||
this.variables = $tw.utils.extend({},this.defaultVariables);
|
||||
if(options.variables) {
|
||||
@@ -44,7 +43,8 @@ function Server(options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
$tw.utils.extend({},this.defaultVariables,options.variables);
|
||||
// Setup the default required plugins
|
||||
this.requiredPlugins = this.get("required-plugins").split(',');
|
||||
// Initialise CSRF
|
||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||
// Initialize Gzip compression
|
||||
@@ -52,14 +52,24 @@ function Server(options) {
|
||||
// Initialize browser-caching
|
||||
this.enableBrowserCache = this.get("use-browser-cache") === "yes";
|
||||
// Initialise authorization
|
||||
var authorizedUserName = (this.get("username") && this.get("password")) ? this.get("username") : "(anon)";
|
||||
var authorizedUserName;
|
||||
if(this.get("username") && this.get("password")) {
|
||||
authorizedUserName = this.get("username");
|
||||
} else if(this.get("credentials")) {
|
||||
authorizedUserName = "(authenticated)";
|
||||
} else {
|
||||
authorizedUserName = "(anon)";
|
||||
}
|
||||
this.authorizationPrincipals = {
|
||||
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
||||
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
||||
}
|
||||
if(this.get("admin") || authorizedUserName !== "(anon)") {
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
|
||||
}
|
||||
// Load and initialise authenticators
|
||||
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
||||
// console.log("Loading server route " + title);
|
||||
// console.log("Loading authenticator " + title);
|
||||
self.addAuthenticator(authenticatorDefinition.AuthenticatorClass);
|
||||
});
|
||||
// Load route handlers
|
||||
@@ -71,15 +81,21 @@ function Server(options) {
|
||||
this.listenOptions = null;
|
||||
this.protocol = "http";
|
||||
var tlsKeyFilepath = this.get("tls-key"),
|
||||
tlsCertFilepath = this.get("tls-cert");
|
||||
tlsCertFilepath = this.get("tls-cert"),
|
||||
tlsPassphrase = this.get("tls-passphrase");
|
||||
if(tlsCertFilepath && tlsKeyFilepath) {
|
||||
this.listenOptions = {
|
||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8")
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
|
||||
passphrase: tlsPassphrase || ''
|
||||
};
|
||||
this.protocol = "https";
|
||||
}
|
||||
this.transport = require(this.protocol);
|
||||
// Name the server and init the boot state
|
||||
this.servername = $tw.utils.transliterateToSafeASCII(this.get("server-name") || this.wiki.getTiddlerText("$:/SiteTitle") || "TiddlyWiki5");
|
||||
this.boot.origin = this.get("origin")? this.get("origin"): this.protocol+"://"+this.get("host")+":"+this.get("port");
|
||||
this.boot.pathPrefix = this.get("path-prefix") || "";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,6 +166,7 @@ function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||
Server.prototype.defaultVariables = {
|
||||
port: "8080",
|
||||
host: "127.0.0.1",
|
||||
"required-plugins": "$:/plugins/tiddlywiki/filesystem,$:/plugins/tiddlywiki/tiddlyweb",
|
||||
"root-tiddler": "$:/core/save/all",
|
||||
"root-render-type": "text/plain",
|
||||
"root-serve-type": "text/html",
|
||||
@@ -239,15 +256,15 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||
state.sendResponse = sendResponse.bind(self,request,response);
|
||||
// Get the principals authorized to access this resource
|
||||
var authorizationType = this.methodMappings[request.method] || "readers";
|
||||
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
||||
// Check for the CSRF header if this is a write
|
||||
if(!this.csrfDisable && authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
||||
if(!this.csrfDisable && state.authorizationType === "writers" && request.headers["x-requested-with"] !== "TiddlyWiki") {
|
||||
response.writeHead(403,"'X-Requested-With' header required to login to '" + this.servername + "'");
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Check whether anonymous access is granted
|
||||
state.allowAnon = this.isAuthorized(authorizationType,null);
|
||||
state.allowAnon = this.isAuthorized(state.authorizationType,null);
|
||||
// Authenticate with the first active authenticator
|
||||
if(this.authenticators.length > 0) {
|
||||
if(!this.authenticators[0].authenticateRequest(request,response,state)) {
|
||||
@@ -256,7 +273,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
}
|
||||
}
|
||||
// Authorize with the authenticated username
|
||||
if(!this.isAuthorized(authorizationType,state.authenticatedUsername)) {
|
||||
if(!this.isAuthorized(state.authorizationType,state.authenticatedUsername)) {
|
||||
response.writeHead(401,"'" + state.authenticatedUsername + "' is not authorized to access '" + this.servername + "'");
|
||||
response.end();
|
||||
return;
|
||||
@@ -322,8 +339,16 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
port = process.env[port] || 8080;
|
||||
}
|
||||
// Warn if required plugins are missing
|
||||
if(!this.wiki.getTiddler("$:/plugins/tiddlywiki/tiddlyweb") || !this.wiki.getTiddler("$:/plugins/tiddlywiki/filesystem")) {
|
||||
$tw.utils.warning("Warning: Plugins required for client-server operation (\"tiddlywiki/filesystem\" and \"tiddlywiki/tiddlyweb\") are missing from tiddlywiki.info file");
|
||||
var missing = [];
|
||||
for (var index=0; index<this.requiredPlugins.length; index++) {
|
||||
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
|
||||
missing.push(this.requiredPlugins[index]);
|
||||
}
|
||||
}
|
||||
if(missing.length > 0) {
|
||||
var error = "Warning: Plugin(s) required for client-server operation are missing.\n"+
|
||||
"\""+ missing.join("\", \"")+"\"";
|
||||
$tw.utils.warning(error);
|
||||
}
|
||||
// Create the server
|
||||
var server;
|
||||
|
||||
@@ -32,13 +32,15 @@ exports.startup = function() {
|
||||
template = paramObject.template || "$:/core/templates/single.tiddler.window",
|
||||
width = paramObject.width || "700",
|
||||
height = paramObject.height || "600",
|
||||
top = paramObject.top,
|
||||
left = paramObject.left,
|
||||
variables = $tw.utils.extend({},paramObject,{currentTiddler: title});
|
||||
// Open the window
|
||||
var srcWindow,
|
||||
srcDocument;
|
||||
// In case that popup blockers deny opening a new window
|
||||
try {
|
||||
srcWindow = window.open("","external-" + title,"scrollbars,width=" + width + ",height=" + height),
|
||||
srcWindow = window.open("","external-" + title,"scrollbars,width=" + width + ",height=" + height + (top ? ",top=" + top : "" ) + (left ? ",left=" + left : "" )),
|
||||
srcDocument = srcWindow.document;
|
||||
}
|
||||
catch(e) {
|
||||
|
||||
@@ -639,14 +639,25 @@ Lookup a given tiddler and return a list of all the tiddlers that include it in
|
||||
*/
|
||||
exports.findListingsOfTiddler = function(targetTitle,fieldName) {
|
||||
fieldName = fieldName || "list";
|
||||
var titles = [];
|
||||
this.each(function(tiddler,title) {
|
||||
var list = $tw.utils.parseStringArray(tiddler.fields[fieldName]);
|
||||
if(list && list.indexOf(targetTitle) !== -1) {
|
||||
titles.push(title);
|
||||
}
|
||||
var wiki = this;
|
||||
var listings = this.getGlobalCache("listings-" + fieldName,function() {
|
||||
var listings = Object.create(null);
|
||||
wiki.each(function(tiddler,title) {
|
||||
var list = $tw.utils.parseStringArray(tiddler.fields[fieldName]);
|
||||
if(list) {
|
||||
for(var i = 0; i < list.length; i++) {
|
||||
var listItem = list[i],
|
||||
listing = listings[listItem] || [];
|
||||
if (listing.indexOf(title) === -1) {
|
||||
listing.push(title);
|
||||
}
|
||||
listings[listItem] = listing;
|
||||
}
|
||||
}
|
||||
});
|
||||
return listings;
|
||||
});
|
||||
return titles;
|
||||
return listings[targetTitle] || [];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1201,23 +1212,28 @@ Return an array of tiddler titles that match a search string
|
||||
text: The text string to search for
|
||||
options: see below
|
||||
Options available:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
source: an iterator function for the source tiddlers, called source(iterator),
|
||||
where iterator is called as iterator(tiddler,title)
|
||||
exclude: An array of tiddler titles to exclude from the search
|
||||
invert: If true returns tiddlers that do not contain the specified string
|
||||
caseSensitive: If true forces a case sensitive search
|
||||
field: If specified, restricts the search to the specified field, or an array of field names
|
||||
anchored: If true, forces all but regexp searches to be anchored to the start of text
|
||||
excludeField: If true, the field options are inverted to specify the fields that are not to be searched
|
||||
|
||||
The search mode is determined by the first of these boolean flags to be true
|
||||
literal: searches for literal string
|
||||
whitespace: same as literal except runs of whitespace are treated as a single space
|
||||
regexp: treats the search term as a regular expression
|
||||
words: (default) treats search string as a list of tokens, and matches if all tokens are found, regardless of adjacency or ordering
|
||||
words: (default) treats search string as a list of tokens, and matches if all tokens are found,
|
||||
regardless of adjacency or ordering
|
||||
some: treats search string as a list of tokens, and matches if at least ONE token is found
|
||||
*/
|
||||
exports.search = function(text,options) {
|
||||
options = options || {};
|
||||
var self = this,
|
||||
t,
|
||||
regExpStr="",
|
||||
invert = !!options.invert;
|
||||
// Convert the search string into a regexp for each term
|
||||
var terms, searchTermsRegExps,
|
||||
@@ -1244,7 +1260,18 @@ exports.search = function(text,options) {
|
||||
searchTermsRegExps = null;
|
||||
console.log("Regexp error parsing /(" + text + ")/" + flags + ": ",e);
|
||||
}
|
||||
} else {
|
||||
} else if(options.some) {
|
||||
terms = text.trim().split(/ +/);
|
||||
if(terms.length === 1 && terms[0] === "") {
|
||||
searchTermsRegExps = null;
|
||||
} else {
|
||||
searchTermsRegExps = [];
|
||||
for(t=0; t<terms.length; t++) {
|
||||
regExpStr += (t===0) ? anchor + $tw.utils.escapeRegExp(terms[t]) : "|" + anchor + $tw.utils.escapeRegExp(terms[t]);
|
||||
}
|
||||
searchTermsRegExps.push(new RegExp("(" + regExpStr + ")",flags));
|
||||
}
|
||||
} else { // default: words
|
||||
terms = text.split(/ +/);
|
||||
if(terms.length === 1 && terms[0] === "") {
|
||||
searchTermsRegExps = null;
|
||||
@@ -1255,7 +1282,7 @@ exports.search = function(text,options) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Accumulate the array of fields to be searched or excluded from the search
|
||||
// Accumulate the array of fields to be searched or excluded from the search
|
||||
var fields = [];
|
||||
if(options.field) {
|
||||
if($tw.utils.isArray(options.field)) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
chapter.of: Extended Persistence
|
||||
created: 20140708084850294
|
||||
modified: 20140717181245449
|
||||
modified: 20210720193245000
|
||||
sub.num: 3
|
||||
tags: doc
|
||||
title: Syncadaptor
|
||||
|
||||
A module with ``module-type: syncadaptor`` provides functionality to get a list of tiddlers (this list is provided as ~SkinnyTiddlers, which are normal tiddlers without the text field) and to load, save and delete single tiddlers. A syncadaptor can also provide functions to login and logout so that syncadaptor modules can be used to synchronize tiddlers with a remote server.
|
||||
|
||||
The syncer module only uses one syncadaptor and honours a special [[system tiddler|System Tiddlers]] [[$:/config/SyncFilter]] containing a [[filter string|Tags and Filter Mechanism]]. Tiddlers matching this filter string are not saved to the server with a syncadapter. It uses the [[WebServer API|https://tiddlywiki.com/#WebServer%20API%3A%20Get%20All%20Tiddlers]] to load modified tiddlers from the server, which returns only non-system tiddlers.
|
||||
The syncer module only uses one syncadaptor and honours a special [[system tiddler|System Tiddlers]] [[$:/config/SyncFilter]] containing a [[filter string|Tags and Filter Mechanism]]. Tiddlers matching this filter string are saved to the server with a syncadapter. It uses the [[WebServer API|https://tiddlywiki.com/#WebServer%20API%3A%20Get%20All%20Tiddlers]] to load modified tiddlers from the server, which returns only non-system tiddlers.
|
||||
|
||||
@@ -57,8 +57,19 @@ Tests the filtering mechanism.
|
||||
);
|
||||
});
|
||||
|
||||
describe("With tiddlers in the store unsorted",function() {
|
||||
testWithAndWithoutIndexers();
|
||||
});
|
||||
describe("With tiddlers in the store sorted ascending",function() {
|
||||
testWithAndWithoutIndexers({sort: "ascending"});
|
||||
});
|
||||
describe("With tiddlers in the store sorted descending",function() {
|
||||
testWithAndWithoutIndexers({sort: "descending"});
|
||||
});
|
||||
|
||||
function testWithAndWithoutIndexers(options) {
|
||||
describe("With no indexers", function() {
|
||||
var wiki = setupWiki({enableIndexers: []});
|
||||
var wiki = setupWiki(Object.assign({},options,{enableIndexers: []}));
|
||||
it("should not create indexes when requested not to",function() {
|
||||
expect(wiki.getIndexer("FieldIndexer")).toBe(null);
|
||||
});
|
||||
@@ -66,14 +77,16 @@ Tests the filtering mechanism.
|
||||
});
|
||||
|
||||
describe("With all indexers", function() {
|
||||
var wiki = setupWiki();
|
||||
var wiki = setupWiki(options);
|
||||
if(wiki.getIndexer("FieldIndexer")) {
|
||||
wiki.getIndexer("FieldIndexer").setMaxIndexedValueLength(8); // Note that JoeBloggs is 9, and John is 5
|
||||
}
|
||||
runTests(wiki);
|
||||
});
|
||||
}
|
||||
|
||||
function setupWiki(wikiOptions) {
|
||||
wikiOptions = wikiOptions || {};
|
||||
// Create a wiki
|
||||
var wiki = new $tw.Wiki(wikiOptions);
|
||||
// Add a plugin containing some shadow tiddlers
|
||||
@@ -104,13 +117,12 @@ Tests the filtering mechanism.
|
||||
}
|
||||
}
|
||||
};
|
||||
wiki.addTiddler({
|
||||
var tiddlers = [{
|
||||
title: "$:/ShadowPlugin",
|
||||
text: JSON.stringify(shadowTiddlers),
|
||||
"plugin-type": "plugin",
|
||||
type: "application/json"});
|
||||
// Add a few tiddlers
|
||||
wiki.addTiddler({
|
||||
type: "application/json"
|
||||
},{
|
||||
title: "TiddlerOne",
|
||||
text: "The quick brown fox in $:/TiddlerTwo",
|
||||
tags: ["one"],
|
||||
@@ -119,8 +131,8 @@ Tests the filtering mechanism.
|
||||
slug: "tiddler-one",
|
||||
authors: "Joe Bloggs",
|
||||
modifier: "JoeBloggs",
|
||||
modified: "201304152222"});
|
||||
wiki.addTiddler({
|
||||
modified: "201304152222"
|
||||
},{
|
||||
title: "$:/TiddlerTwo",
|
||||
text: "The rain in Spain\nfalls mainly on the plain and [[a fourth tiddler]]",
|
||||
tags: ["two"],
|
||||
@@ -129,44 +141,75 @@ Tests the filtering mechanism.
|
||||
slug: "tiddler-two",
|
||||
authors: "[[John Doe]]",
|
||||
modifier: "John",
|
||||
modified: "201304152211"});
|
||||
wiki.addTiddler({
|
||||
modified: "201304152211"
|
||||
},{
|
||||
title: "Tiddler Three",
|
||||
text: "The speed of sound in light\n\nThere is no TiddlerZero but TiddlerSix",
|
||||
tags: ["one","two"],
|
||||
cost: "56",
|
||||
value: "80",
|
||||
modifier: "John",
|
||||
modified: "201304162202"});
|
||||
wiki.addTiddler({
|
||||
modified: "201304162202"
|
||||
},{
|
||||
title: "a fourth tiddler",
|
||||
text: "The quality of mercy is not drained by [[Tiddler Three]]",
|
||||
tags: [],
|
||||
cost: "82",
|
||||
value: "72",
|
||||
empty: "not",
|
||||
modifier: "John"});
|
||||
wiki.addTiddler({
|
||||
modifier: "John"
|
||||
},{
|
||||
title: "one",
|
||||
text: "This is the text of tiddler [[one]]",
|
||||
list: "[[Tiddler Three]] [[TiddlerOne]]",
|
||||
empty: "",
|
||||
modifier: "John"});
|
||||
wiki.addTiddler({
|
||||
modifier: "John"
|
||||
},{
|
||||
title: "hasList",
|
||||
text: "This is the text of tiddler [[hasList]]",
|
||||
list: "[[Tiddler Three]] [[TiddlerOne]]",
|
||||
modifier: "PMario"});
|
||||
wiki.addTiddler({
|
||||
modifier: "PMario"
|
||||
},{
|
||||
title: "has filter",
|
||||
text: "This is the text of tiddler [[has filter]]",
|
||||
filter: "[[Tiddler Three]] [[TiddlerOne]] [subfilter{hasList!!list}]",
|
||||
modifier: "PMario"});
|
||||
wiki.addTiddler({
|
||||
modifier: "PMario"
|
||||
},{
|
||||
title: "filter regexp test",
|
||||
text: "Those strings have been used to create the `regexp = /[+|\-|~]?([[](?:[^\]])*\]+)|([+|-|~|\S]\S*)/;`",
|
||||
filter: "+aaa -bbb ~ccc aaaaaabbbbbbbbaa \"bb'b\" 'cc\"c' [[abc]] [[tiddler with spaces]] [is[test]] [is[te st]] a s df [enlist<hugo>] +[enlist:raw{test with spaces}] [enlist:raw{test with spaces}] [[a a]] [[ ] [ ]] [[ [hugo]] [subfilter{Story/Tower of Hanoi/A-C Sequence}]",
|
||||
modifier: "PMario"});
|
||||
modifier: "PMario"
|
||||
}];
|
||||
// Load the tiddlers in the required order
|
||||
var fnCompare;
|
||||
switch(wikiOptions.sort) {
|
||||
case "ascending":
|
||||
fnCompare = function(a,b) {
|
||||
if(a.title < b.title) {
|
||||
return -1;
|
||||
} else if(a.title > b.title) {
|
||||
return +1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "descending":
|
||||
fnCompare = function(a,b) {
|
||||
if(a.title < b.title) {
|
||||
return +1;
|
||||
} else if(a.title > b.title) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
if(fnCompare) {
|
||||
tiddlers.sort(fnCompare);
|
||||
}
|
||||
wiki.addTiddlers(tiddlers);
|
||||
// Unpack plugin tiddlers
|
||||
wiki.readPluginInfo();
|
||||
wiki.registerPluginTiddlers("plugin");
|
||||
@@ -197,7 +240,7 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[!modifier[JoeBloggs]then[Susi]]").join(",")).toBe("Susi,Susi,Susi,Susi,Susi,Susi,Susi,Susi");
|
||||
expect(wiki.filterTiddlers("[modifier[DaveBloggs]then[Susi]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[modifier[JoeBloggs]else[Susi]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!modifier[JoeBloggs]else[Susi]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!modifier[JoeBloggs]else[Susi]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[modifier[DaveBloggs]else[Susi]]").join(",")).toBe("Susi");
|
||||
});
|
||||
|
||||
@@ -211,6 +254,8 @@ Tests the filtering mechanism.
|
||||
it("should handle the lookup operator", function() {
|
||||
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,,Tidd");
|
||||
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler]]").join(",")).toBe("Missing inaction from TiddlerOne,8,Tidd");
|
||||
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup:8[Tiddler],[text]]").join(",")).toBe("Missing inaction from TiddlerOne,8,Tidd");
|
||||
expect(wiki.filterTiddlers("Six Seventh 8 +[lookup[Tiddler],[tags]]").join(",")).toBe(",one,one");
|
||||
});
|
||||
|
||||
it("should retrieve shadow tiddlers", function() {
|
||||
@@ -219,31 +264,31 @@ Tests the filtering mechanism.
|
||||
|
||||
it("should handle the title operator", function() {
|
||||
expect(wiki.filterTiddlers("TiddlerOne [title[$:/TiddlerTwo]] [[Tiddler Three]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("TiddlerOne [title[$:/TiddlerTwo]] [[Tiddler Three]] [[A Missing Tiddler]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three,A Missing Tiddler");
|
||||
});
|
||||
|
||||
it("should handle the field operator", function() {
|
||||
expect(wiki.filterTiddlers("[modifier[JoeBloggs]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!modifier[JoeBloggs]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!is[system]!modifier[JoeBloggs]]").join(",")).toBe("Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!modifier[JoeBloggs]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!is[system]!modifier[JoeBloggs]]").join(",")).toBe("a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[field:modifier[JoeBloggs]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!field:modifier[JoeBloggs]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!is[system]!field:modifier[JoeBloggs]]").join(",")).toBe("Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[modifier[John]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one");
|
||||
expect(wiki.filterTiddlers("[!modifier[John]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!is[system]!modifier[John]]").join(",")).toBe("TiddlerOne,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[field:modifier[John]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one");
|
||||
expect(wiki.filterTiddlers("[!field:modifier[John]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!is[system]!field:modifier[John]]").join(",")).toBe("TiddlerOne,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!field:modifier[JoeBloggs]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!is[system]!field:modifier[JoeBloggs]]").join(",")).toBe("a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[modifier[John]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!modifier[John]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,has filter,hasList,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!is[system]!modifier[John]]").join(",")).toBe("filter regexp test,has filter,hasList,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[field:modifier[John]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!field:modifier[John]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,has filter,hasList,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!is[system]!field:modifier[John]]").join(",")).toBe("filter regexp test,has filter,hasList,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the regexp operator", function() {
|
||||
expect(wiki.filterTiddlers("[regexp[id]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[!regexp[id]]").join(",")).toBe("$:/ShadowPlugin,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[regexp[Tid]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[regexp[(?i)Tid]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[!regexp[Tid(?i)]]").join(",")).toBe("$:/ShadowPlugin,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[regexp[id]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!regexp[id]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,has filter,hasList,one");
|
||||
expect(wiki.filterTiddlers("[regexp[Tid]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[regexp[(?i)Tid]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!regexp[Tid(?i)]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,has filter,hasList,one");
|
||||
});
|
||||
|
||||
// The following 2 tests should write a log -> WARNING: Filter modifier has a deprecated regexp operand XXXX
|
||||
@@ -253,7 +298,7 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[modifier/JoeBloggs/]").join(",")).toBe("TiddlerOne");
|
||||
expect(console.log).toHaveBeenCalledWith("WARNING: Filter", "modifier", "has a deprecated regexp operand", /JoeBloggs/);
|
||||
console.log.calls.reset();
|
||||
expect(wiki.filterTiddlers("[modifier/Jo/]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one");
|
||||
expect(wiki.filterTiddlers("[modifier/Jo/]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,one,Tiddler Three,TiddlerOne");
|
||||
expect(console.log).toHaveBeenCalledWith("WARNING: Filter", "modifier", "has a deprecated regexp operand", /Jo/);
|
||||
});
|
||||
|
||||
@@ -268,15 +313,15 @@ Tests the filtering mechanism.
|
||||
});
|
||||
|
||||
it("should handle the prefix operator", function() {
|
||||
expect(wiki.filterTiddlers("[prefix[Tiddler]]").join(",")).toBe("TiddlerOne,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[prefix[Tiddler]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[prefix[nothing]]").join(",")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle the sort and sortcs operators", function() {
|
||||
expect(wiki.filterTiddlers("[sort[title]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!sort[title]]").join(",")).toBe("TiddlerOne,Tiddler Three,one,hasList,has filter,filter regexp test,a fourth tiddler,$:/TiddlerTwo,$:/ShadowPlugin");
|
||||
expect(wiki.filterTiddlers("[sort[modified]]").join(",")).toBe("$:/ShadowPlugin,a fourth tiddler,one,hasList,has filter,filter regexp test,$:/TiddlerTwo,TiddlerOne,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!sort[modified]]").join(",")).toBe("Tiddler Three,TiddlerOne,$:/TiddlerTwo,$:/ShadowPlugin,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[sort[modified]]").join(",")).toBe("$:/ShadowPlugin,a fourth tiddler,filter regexp test,has filter,hasList,one,$:/TiddlerTwo,TiddlerOne,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[!sort[modified]]").join(",")).toBe("Tiddler Three,TiddlerOne,$:/TiddlerTwo,$:/ShadowPlugin,a fourth tiddler,filter regexp test,has filter,hasList,one");
|
||||
// Temporarily commenting out the following two lines because of platform differences for localeCompare between the browser and Node.js
|
||||
// expect(wiki.filterTiddlers("[sortcs[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler,one");
|
||||
// expect(wiki.filterTiddlers("[!sortcs[title]]").join(",")).toBe("one,a fourth tiddler,TiddlerOne,Tiddler Three,$:/TiddlerTwo");
|
||||
@@ -326,10 +371,10 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[all[shadows]tag[two]]").join(",")).toBe("$:/TiddlerFive");
|
||||
expect(wiki.filterTiddlers("[all[shadows+tiddlers]tag[two]]").join(",")).toBe("$:/TiddlerFive,$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[all[tiddlers+shadows]tag[two]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,$:/TiddlerFive");
|
||||
expect(wiki.filterTiddlers("[all[shadows+tiddlers]]").join(",")).toBe("$:/TiddlerFive,TiddlerSix,TiddlerSeventh,Tiddler8,$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[all[tiddlers+shadows]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test,$:/TiddlerFive,TiddlerSix,TiddlerSeventh,Tiddler8");
|
||||
expect(wiki.filterTiddlers("[all[shadows+tiddlers]]").join(",")).toBe("$:/TiddlerFive,TiddlerSix,TiddlerSeventh,Tiddler8,$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[all[tiddlers+shadows]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne,$:/TiddlerFive,TiddlerSix,TiddlerSeventh,Tiddler8");
|
||||
expect(wiki.filterTiddlers("[all[tiddlers]tag[two]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[all[orphans+tiddlers+tags]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,hasList,has filter,filter regexp test,two,one");
|
||||
expect(wiki.filterTiddlers("[all[orphans+tiddlers+tags]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,Tiddler Three,TiddlerOne,two,one");
|
||||
});
|
||||
|
||||
it("should handle the tags operator", function() {
|
||||
@@ -340,11 +385,11 @@ Tests the filtering mechanism.
|
||||
it("should handle the match operator", function() {
|
||||
expect(wiki.filterTiddlers("[match[TiddlerOne]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("TiddlerOne TiddlerOne =[match[TiddlerOne]]").join(",")).toBe("TiddlerOne,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!match[TiddlerOne]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!match[TiddlerOne]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[match:casesensitive[tiddlerone]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[!match:casesensitive[tiddlerone]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!match:casesensitive[tiddlerone]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[match:caseinsensitive[tiddlerone]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!match:caseinsensitive[tiddlerone]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!match:caseinsensitive[tiddlerone]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three");
|
||||
});
|
||||
|
||||
it("should handle the tagging operator", function() {
|
||||
@@ -393,6 +438,11 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[list[TiddlerSeventh]sort[title]]").join(",")).toBe("a fourth tiddler,MissingTiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[tag[one]list[TiddlerSeventh]sort[title]]").join(",")).toBe("a fourth tiddler,MissingTiddler,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the listed operator", function() {
|
||||
expect(wiki.filterTiddlers("TiddlerOne MissingTiddler +[listed[]]").join(",")).toBe('hasList,one');
|
||||
expect(wiki.filterTiddlers("one two +[listed[tags]]").join(",")).toBe('TiddlerOne,$:/TiddlerTwo,Tiddler Three');
|
||||
});
|
||||
|
||||
it("should handle the next operator", function() {
|
||||
expect(wiki.filterTiddlers("[[Tiddler Three]next[TiddlerSeventh]]").join(",")).toBe("a fourth tiddler");
|
||||
@@ -414,21 +464,54 @@ Tests the filtering mechanism.
|
||||
expect(wiki.filterTiddlers("[search:modifier:regexp[(d|bl)o(ggs|e)]sort[title]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:-modifier,authors:[g]sort[title]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[search:*:[g]sort[title]]").join(",")).toBe("$:/ShadowPlugin,filter regexp test,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:text:anchored[the]]").join(",")).toBe("TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[search:text:anchored[the]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
|
||||
it("should yield search results where 'default' search finds at least 1 token", function() {
|
||||
expect(wiki.filterTiddlers("[search::some[one two]sort[title]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,one,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should yield search results where 'title' finds at least one token", function() {
|
||||
expect(wiki.filterTiddlers("[search:title:some[tiddler]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:title:some[tiddler one]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,one,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should yield search results where 'tags' finds at least one token", function() {
|
||||
expect(wiki.filterTiddlers("[search:tags:some[one]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:tags:some[two]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[search:tags:some[two one]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should yield search results where 'tags' finds at least one token / casesensitive", function() {
|
||||
expect(wiki.filterTiddlers("[search:tags:some[ONE]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:tags:some,casesensitive[two ONE]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
});
|
||||
|
||||
it("should yield search results where 'tags' finds at least one token / anchored", function() {
|
||||
expect(wiki.filterTiddlers("[search:tags:some,anchored[one]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:tags:some,anchored[two]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
// search:title
|
||||
expect(wiki.filterTiddlers("[search:title:some,anchored[tiddler]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:title:some,anchored[tiddler one]sort[title]]").join(",")).toBe("one,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should yield search results where 'tags' finds at least one token / anchored & casesensitive", function() {
|
||||
expect(wiki.filterTiddlers("[search:title:some,anchored,casesensitive[Tiddler one]sort[title]]").join(",")).toBe("one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[search:title:some,anchored,casesensitive[Tiddler ONE]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should yield search results that have search tokens spread across different fields", function() {
|
||||
expect(wiki.filterTiddlers("[search[fox one]sort[title]]").join(",")).toBe("TiddlerOne");
|
||||
});
|
||||
|
||||
|
||||
it("should handle the each operator", function() {
|
||||
expect(wiki.filterTiddlers("[each[modifier]sort[title]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,hasList,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[each[modifier]sort[title]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,filter regexp test,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[each:list-item[tags]sort[title]]").join(",")).toBe("one,two");
|
||||
expect(wiki.filterTiddlers("[each:list-item[authors]sort[title]]").join(",")).toBe("Bloggs,Joe,John Doe");
|
||||
});
|
||||
|
||||
it("should handle the eachday operator", function() {
|
||||
expect(wiki.filterTiddlers("[eachday[modified]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[eachday[modified]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
});
|
||||
|
||||
it("should handle the sameday operator", function() {
|
||||
@@ -456,7 +539,7 @@ Tests the filtering mechanism.
|
||||
});
|
||||
|
||||
it("should handle the '[is[missing]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[all[]]").join(",")).toBe("$:/ShadowPlugin,TiddlerOne,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,one,hasList,has filter,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[all[]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[all[missing]]").join(",")).toBe("TiddlerZero");
|
||||
expect(wiki.filterTiddlers("[!is[missing]sort[title]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,a fourth tiddler,filter regexp test,has filter,hasList,one,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]is[missing]]").join(",")).toBe("");
|
||||
@@ -467,11 +550,11 @@ Tests the filtering mechanism.
|
||||
|
||||
it("should handle the '[is[orphan]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[orphan]sort[title]]").join(",")).toBe("a fourth tiddler,filter regexp test,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!is[orphan]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,one,hasList,has filter");
|
||||
expect(wiki.filterTiddlers("[!is[orphan]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,has filter,hasList,one,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]is[orphan]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]!is[orphan]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]is[orphan]sort[title]]").join(",")).toBe("a fourth tiddler,filter regexp test,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]!is[orphan]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,one,hasList,has filter");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]!is[orphan]]").join(",")).toBe("$:/ShadowPlugin,$:/TiddlerTwo,has filter,hasList,one");
|
||||
});
|
||||
|
||||
});
|
||||
@@ -785,10 +868,10 @@ Tests the filtering mechanism.
|
||||
rootWidget.setVariable("sort2","[get[text]else[]length[]]");
|
||||
rootWidget.setVariable("sort3","[{!!value}divide{!!cost}]");
|
||||
rootWidget.setVariable("sort4","[{!!title}]");
|
||||
expect(wiki.filterTiddlers("[sortsub:number<sort1>]",anchorWidget).join(",")).toBe("one,hasList,TiddlerOne,has filter,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!sortsub:number<sort1>]",anchorWidget).join(",")).toBe("filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,TiddlerOne,has filter,hasList,one");
|
||||
expect(wiki.filterTiddlers("[sortsub:string<sort1>]",anchorWidget).join(",")).toBe("TiddlerOne,has filter,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test,one,hasList");
|
||||
expect(wiki.filterTiddlers("[!sortsub:string<sort1>]",anchorWidget).join(",")).toBe("hasList,one,filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,TiddlerOne,has filter");
|
||||
expect(wiki.filterTiddlers("[sortsub:number<sort1>]",anchorWidget).join(",")).toBe("one,hasList,has filter,TiddlerOne,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test");
|
||||
expect(wiki.filterTiddlers("[!sortsub:number<sort1>]",anchorWidget).join(",")).toBe("filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,has filter,TiddlerOne,hasList,one");
|
||||
expect(wiki.filterTiddlers("[sortsub:string<sort1>]",anchorWidget).join(",")).toBe("has filter,TiddlerOne,$:/TiddlerTwo,Tiddler Three,$:/ShadowPlugin,a fourth tiddler,filter regexp test,one,hasList");
|
||||
expect(wiki.filterTiddlers("[!sortsub:string<sort1>]",anchorWidget).join(",")).toBe("hasList,one,filter regexp test,a fourth tiddler,$:/ShadowPlugin,$:/TiddlerTwo,Tiddler Three,has filter,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[sortsub:number<sort2>]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,a fourth tiddler,Tiddler Three,$:/TiddlerTwo,filter regexp test,$:/ShadowPlugin");
|
||||
expect(wiki.filterTiddlers("[!sortsub:number<sort2>]",anchorWidget).join(",")).toBe("$:/ShadowPlugin,filter regexp test,$:/TiddlerTwo,Tiddler Three,a fourth tiddler,has filter,hasList,TiddlerOne,one");
|
||||
expect(wiki.filterTiddlers("[sortsub:string<sort2>]",anchorWidget).join(",")).toBe("one,TiddlerOne,hasList,has filter,$:/ShadowPlugin,a fourth tiddler,Tiddler Three,$:/TiddlerTwo,filter regexp test");
|
||||
|
||||
@@ -392,10 +392,10 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
rootWidget.setVariable("larger-than-18","[get[text]length[]compare:integer:gteq[18]]");
|
||||
rootWidget.setVariable("nr","18");
|
||||
rootWidget.setVariable("larger-than-18-with-var","[get[text]length[]compare:integer:gteq<nr>]");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :filter[get[text]length[]compare:integer:gteq[18]]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]]",anchorWidget).join(",")).toBe("Sparkling water,Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18>]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18-with-var>]",anchorWidget).join(",")).toBe("Red wine,Cheesecake,Chocolate Cake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :filter[get[text]length[]compare:integer:gteq[18]]",anchorWidget).join(",")).toBe("Cheesecake,Chocolate Cake,Red wine");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]]",anchorWidget).join(",")).toBe("Cheesecake,Chocolate Cake,Red wine,Sparkling water");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18>]",anchorWidget).join(",")).toBe("Cheesecake,Chocolate Cake,Red wine");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]filter<larger-than-18-with-var>]",anchorWidget).join(",")).toBe("Cheesecake,Chocolate Cake,Red wine");
|
||||
});
|
||||
|
||||
it("should handle the :sort prefix", function() {
|
||||
@@ -405,7 +405,7 @@ describe("'reduce' and 'intersection' filter prefix tests", function() {
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :sort:number:[get[text]length[]]").join(",")).toBe("Sparkling water,Chocolate Cake,Red wine,Cheesecake");
|
||||
expect(wiki.filterTiddlers("[tag[textexample]] :sort:number:reverse[get[text]length[]]").join(",")).toBe("Cheesecake,Red wine,Chocolate Cake,Sparkling water");
|
||||
expect(wiki.filterTiddlers("[tag[notatag]] :sort:number[get[price]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string[{!!title}]").join(",")).toBe("Cheesecake,cheesecake,Chocolate Cake,chocolate cake,Persian love cake,Pound cake");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string[{!!title}]").join(",")).toBe("cheesecake,Cheesecake,chocolate cake,Chocolate Cake,Persian love cake,Pound cake");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string:casesensitive[{!!title}]").join(",")).toBe("Cheesecake,Chocolate Cake,Persian love cake,Pound cake,cheesecake,chocolate cake");
|
||||
expect(wiki.filterTiddlers("[tag[cakes]] :sort:string:casesensitive,reverse[{!!title}]").join(",")).toBe("chocolate cake,cheesecake,Pound cake,Persian love cake,Chocolate Cake,Cheesecake");
|
||||
});
|
||||
|
||||
@@ -102,6 +102,25 @@ function runTests(wiki,wikiOptions) {
|
||||
expect(wiki.filterTiddlers("[tag[TiddlerSeventh]]").join(",")).toBe("Tiddler10,TiddlerOne,Tiddler Three,Tiddler11,Tiddler9,a fourth tiddler");
|
||||
});
|
||||
|
||||
it("should apply identical tag ordering irrespective of tag creation order", function () {
|
||||
var wiki;
|
||||
wiki = new $tw.Wiki(wikiOptions);
|
||||
wiki.addTiddler({ title: "A", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "B", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "C", text: "", tags: "sortTag"});
|
||||
expect(wiki.filterTiddlers("[tag[sortTag]]").join(',')).toBe("A,B,C");
|
||||
wiki = new $tw.Wiki(wikiOptions);
|
||||
wiki.addTiddler({ title: "A", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "C", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "B", text: "", tags: "sortTag"});
|
||||
expect(wiki.filterTiddlers("[tag[sortTag]]").join(',')).toBe("A,B,C");
|
||||
wiki = new $tw.Wiki(wikiOptions);
|
||||
wiki.addTiddler({ title: "C", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "B", text: "", tags: "sortTag"});
|
||||
wiki.addTiddler({ title: "A", text: "", tags: "sortTag"});
|
||||
expect(wiki.filterTiddlers("[tag[sortTag]]").join(',')).toBe("A,B,C");
|
||||
});
|
||||
|
||||
// Tests for issue (#3296)
|
||||
it("should apply tag ordering in order of dependency", function () {
|
||||
var wiki = new $tw.Wiki(wikiOptions);
|
||||
|
||||
@@ -169,6 +169,16 @@ describe("Utility tests", function() {
|
||||
expect(cv("1.1.1","1.1.2")).toEqual(-1);
|
||||
});
|
||||
|
||||
it("should insert strings into sorted arrays", function() {
|
||||
expect($tw.utils.insertSortedArray([],"a").join(",")).toEqual("a");
|
||||
expect($tw.utils.insertSortedArray(["b","c","d"],"a").join(",")).toEqual("a,b,c,d");
|
||||
expect($tw.utils.insertSortedArray(["b","c","d"],"d").join(",")).toEqual("b,c,d");
|
||||
expect($tw.utils.insertSortedArray(["b","c","d"],"f").join(",")).toEqual("b,c,d,f");
|
||||
expect($tw.utils.insertSortedArray(["b","c","d","e"],"f").join(",")).toEqual("b,c,d,e,f");
|
||||
expect($tw.utils.insertSortedArray(["b","c","g"],"f").join(",")).toEqual("b,c,f,g");
|
||||
expect($tw.utils.insertSortedArray(["b","c","d"],"ccc").join(",")).toEqual("b,c,ccc,d");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
|
||||
@@ -6,3 +6,8 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
<<.operator-example 1 "[all[shadows+tiddlers]tag[$:/tags/PageControls]lookup[$:/config/PageControlButtons/Visibility/]]" "Retrieve the visibility status of each page control button">>
|
||||
<<.operator-example 2 "[all[shadows+tiddlers]tag[$:/tags/PageControls]lookup:show[$:/config/PageControlButtons/Visibility/]]" "Retrieve the visibility status of each page control button, this time with a default value">>
|
||||
<<.operator-example 3 "[all[tiddlers]has[plugin-type]removeprefix[$:/plugins/tiddlywiki/]lookup:missing-description:field[$:/plugins/tiddlywiki/],[description]]" "Retrieve the description of all plugin-tiddlers that are in the `$:/plugins/tiddlywiki/` namespace.">>
|
||||
<<.operator-example 4 "OriginalTiddlerPaths +[lookup:missing-index:index[$:/config/],[HelloThere]]" "Lookup the original tiddler path on disk for the [[Hello There]] tiddler.">>
|
||||
<<.operator-example 5 "OriginalTiddlerPaths +[lookup:missing-index:index[$:/config/],[MissingTiddler]]" "Lookup the original tiddler path on disk for the [[MissingTiddler]] tiddler.">>
|
||||
<<.operator-example 6 "HistoryList MissingHistoryList +[lookup:missing-0:index[$:/]]" "Retrieve index `0` from the `$:/HistoryList` and `$:/MissingHistoryList`.">>
|
||||
<<.operator-example 7 "OriginalTiddlerPaths MissingTiddlerPaths +[lookup:missing-tiddler:index[$:/config/],[$:/key-test]]" "Retrieve index `$:/key-test` from `$:/config/OriginalTiddlerPaths` and `$:/config/MissingTiddlerPaths`.">>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20150124104508000
|
||||
modified: 20181025082022690
|
||||
modified: 20211129122755444
|
||||
tags: [[search Operator]] [[Operator Examples]]
|
||||
title: search Operator (Examples)
|
||||
type: text/vnd.tiddlywiki
|
||||
@@ -13,3 +13,8 @@ type: text/vnd.tiddlywiki
|
||||
<$macrocall $name=".operator-example" n="7" eg="[!is[system]search::literal[the first]]" ie="non-system tiddlers containing a case-insensitive match for the literal phrase <<.word 'the first'>>"/>
|
||||
<$macrocall $name=".operator-example" n="8" eg="[!is[system]search::literal,casesensitive[The first]]" ie="non-system tiddlers containing a case-sensitive match for the literal phrase <<.word 'The first'>>"/>
|
||||
<$macrocall $name=".operator-example" n="9" eg="[search:caption,description:casesensitive,words[arch]]" ie="any tiddlers containing a case-sensitive match for the word `arch` in their <<.field caption>> or <<.field description>> fields"/>
|
||||
<$macrocall $name=".operator-example" n="10" eg="[search:tags:some[how test]]" ie="any tiddlers containing at least 1 of the search terms in the field: <<.field tags>>"/>
|
||||
<$macrocall $name=".operator-example" n="11" eg="[search:tags:some,casesensitive[how test]]" ie="any tiddlers containing at least 1 of the case-sensitive search terms in the field: <<.field tags>>"/>
|
||||
<$macrocall $name=".operator-example" n="12" eg="[search:tags,title:some,anchored[how test]]" ie="any tiddlers containing at least 1 of anchored search terms in the fields: <<.field tags>> and <<.field title>>"/>
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,42 @@
|
||||
caption: lookup
|
||||
created: 20170907103639431
|
||||
modified: 20170907144703051
|
||||
modified: 20210116081305739
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-output: the lookup values corresponding to each input title
|
||||
op-parameter: prefix applied to input titles to yield title of lookup tiddler from which value is retrieved
|
||||
op-parameter-name: P
|
||||
op-purpose: applies a prefix to each input title to yield the title of a tiddler from which the final value is retrieved
|
||||
op-suffix: the default value to be used for missing lookups
|
||||
op-suffix-name: D
|
||||
op-output: the lookup values corresponding to each lookup tiddler
|
||||
op-parameter: prefix applied to input titles to yield title of lookup tiddler from which value is retrieved. Now accepts 1 or 2 parameters, see below for details
|
||||
op-parameter-name: P, T
|
||||
op-purpose: applies a prefix to each input title to yield the title of a tiddler from which the final value is retrieved. With a single parameter, the default field is "text" and the default index is "0". If a second parameter is provided, that becomes the target field or index.
|
||||
op-suffix: the default value to be used for missing lookups. This operator can now accept a second suffix of `:index`, see below for details
|
||||
op-suffix-name: D, I
|
||||
tags: [[Filter Operators]]
|
||||
title: lookup Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.1.15">>
|
||||
|
||||
The action of this operator is as follows:
|
||||
The action of this operator is as follows with 1 parameter:
|
||||
|
||||
* Apply the specified prefix to each input tiddler title, yielding a new list of tiddler titles
|
||||
* Transclude the value of each of those tiddlers
|
||||
** Substitute the default value for missing or empty tiddlers
|
||||
* Transclude the value of the `text` field each of those tiddlers
|
||||
** Substitute the default value for missing or empty values
|
||||
* Return the list of values
|
||||
|
||||
<<.from-version "5.2.2">>
|
||||
|
||||
The use of the `:index` second suffix changes the default lookup location from field: `text` to index: `0`. This is used if no 2nd parameter is provided.
|
||||
|
||||
The action of this operator is as follows with 2 parameters:
|
||||
|
||||
If there are two parameters provided, use the second parameter as the target field or index.
|
||||
|
||||
<<.note """If there is only one parameter given, the filter checks for a second suffix equal to "index". If this suffix is found, the default target index is "0".
|
||||
In all other cases, the default target field is "text".""">>
|
||||
|
||||
Then:
|
||||
|
||||
* Apply the specified prefix to each input tiddler title, yielding a new list of tiddler titles
|
||||
* Transclude the value of the target field or index
|
||||
** Substitute the default value for missing or empty values
|
||||
* Return the list of values
|
||||
|
||||
<<.operator-examples "lookup">>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
caption: search
|
||||
created: 20140410103123179
|
||||
modified: 20190731212738712
|
||||
modified: 20211129120739275
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-neg-output: those input tiddlers in which <<.em not>> all of the search terms can be found
|
||||
op-output: those input tiddlers in which <<.em all>> of the search terms can be found in the value of field <<.place F>>
|
||||
op-parameter: one or more search terms, separated by spaces, or a literal search string
|
||||
op-purpose: filter the input by searching tiddler content
|
||||
op-suffix: the <<.op search>> operator uses a rich suffix, see below for details
|
||||
tags: [[Filter Operators]] [[Common Operators]] [[Field Operators]] [[Negatable Operators]]
|
||||
title: search Operator
|
||||
type: text/vnd.tiddlywiki
|
||||
caption: search
|
||||
op-purpose: filter the input by searching tiddler content
|
||||
op-input: a [[selection of titles|Title Selection]]
|
||||
op-suffix: the <<.op search>> operator uses a rich suffix, see below for details
|
||||
op-parameter: one or more search terms, separated by spaces, or a literal search string
|
||||
op-output: those input tiddlers in which <<.em all>> of the search terms can be found in the value of field <<.place F>>
|
||||
op-neg-output: those input tiddlers in which <<.em not>> all of the search terms can be found
|
||||
|
||||
<<.from-version "5.1.18">> The search filter operator was significantly enhanced in 5.1.18. Earlier versions do not support the extended syntax and therefore do not permit searching multiple fields, or the ''literal'' or ''casesensitive'' options.
|
||||
|
||||
@@ -38,7 +38,8 @@ The available flags are:
|
||||
** ''literal'': considers the search string to be a literal string, and requires an exact match
|
||||
** ''whitespace'': considers the search string to be a literal string, but will consider all runs of whitespace to be equivalent to a single space. Thus `A B` matches `A B`
|
||||
** ''regexp'': treats the search string as a regular expression. Note that the ''regexp'' option obviates the need for the older <<.olink regexp>> operator.
|
||||
** ''words'': (the default) treats the search string as a list of tokens separated by whitespace, and matches if all of the tokens appear in the string (regardless of ordering and whether there is other text in between)
|
||||
** ''words'': (the default) treats the search string as a list of tokens separated by whitespace, and matches if ''all of the tokens'' appear in the string (regardless of ordering and whether there is other text in between)
|
||||
** ''some'': <<.from-version "5.2.2">> treats the search string as a list of tokens separated by whitespace, and matches if ''at least one'' of the tokens appear in the string
|
||||
* ''casesensitive'': if present, this flag forces a case-sensitive match, where upper and lower case letters are considered different. By default, upper and lower case letters are considered identical for matching purposes.
|
||||
* ''anchored'': <<.from-version "5.1.20">> anchors the search to the start of the string (applies to ''whitespace'', ''literal'' and ''words'' modes)
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
caption: tm-open-window
|
||||
created: 20160424181447704
|
||||
modified: 20211117042202771
|
||||
modified: 20220219125413255
|
||||
tags: Messages
|
||||
title: WidgetMessage: tm-open-window
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
The `tm-open-window` [[message|Message]] opens a tiddler in a new //browser// window. If no parameters are specified, the current tiddler is opened in a new window. Similiar to `tm-modal` any additional parameters passed via the <<.param "paramObject">> are provided as variables to the new window.
|
||||
The `tm-open-window` [[message|Messages]] opens a tiddler in a new //browser// window. If no parameters are specified, the current tiddler is opened in a new window. Similiar to `tm-modal` any additional parameters passed via the <<.param "paramObject">> are provided as variables to the new window.
|
||||
|
||||
|!Name |!Description |
|
||||
|param |Title of the tiddler to be opened in a new browser window, defaults to <<.var "currentTiddler">> if empty |
|
||||
@@ -13,12 +13,14 @@ The `tm-open-window` [[message|Message]] opens a tiddler in a new //browser// wi
|
||||
|windowTitle |Title string for the opened window |
|
||||
|width |Width of the new browser window |
|
||||
|height |Height of the new browser window |
|
||||
|left|<<.from-version "5.2.2">> Optional, left position of new browser window|
|
||||
|top|<<.from-version "5.2.2">> Optional, top position of new browser window|
|
||||
|paramObject |Hashmap of variables to be provided to the modal, contains all extra parameters passed to the widget sending the message. |
|
||||
|
||||
The `tm-open-window` message is best generated with the ActionSendMessageWidget, which in turn is triggered by a widget such as the ButtonWidget. It is handled by the core itself.
|
||||
|
||||
<<.tip """When used with the ActionSendMessage Widget, <<.param 'param'>> becomes <<.param '$param'>> """>>
|
||||
<<.tip """Parameters <<.param template>>, <<.param windowTitle>>, <<.param width>>, and <<.param height>> require the ActionSendMessageWidget.""">>
|
||||
<<.tip """When used with the ActionSendMessageWidget, <<.param 'param'>> becomes <<.param '$param'>> """>>
|
||||
<<.tip """Parameters <<.param template>>, <<.param windowTitle>>, <<.param width>>, <<.param height>>, <<.param left>> and <<.param top>> require the ActionSendMessageWidget.""">>
|
||||
|
||||
|
||||
<$macrocall $name='wikitext-example-without-html'
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
created: 20180702160923664
|
||||
modified: 20180703100549667
|
||||
modified: 20211111023610539
|
||||
tags: [[WebServer Guides]]
|
||||
title: Using HTTPS
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
By default, TiddlyWiki's WebServer serves resources over the insecure HTTP protocol. The risk is minimal if it is only being used within a private, trusted network but in many situations it is desirable to use a secure HTTPS connection.
|
||||
|
||||
HTTPS requires the server to be configured with a certificate via a "cert" file and a "key" file, configured via the [[tls-cert|WebServer Parameter: tls-cert]] and [[tls-key|WebServer Parameter: tls-key]] parameters
|
||||
HTTPS requires the server to be configured with a certificate via a "cert" file and a "key" file, configured via the [[tls-cert|WebServer Parameter: tls-cert]] and [[tls-key|WebServer Parameter: tls-key]] parameters.
|
||||
|
||||
<<.from-version "5.2.2">> The optional [[tls-passphrase|WebServer Parameter: tls-passphrase]] parameter allows the server to use certificate files that have been generated with a passphrase/password.
|
||||
|
||||
Certificates can be obtained from a certification authority such as https://letsencrypt.org/, or you can create a self-signed certificate for internal testing.
|
||||
|
||||
@@ -17,3 +19,16 @@ openssl req -newkey rsa:2048 -new -nodes -keyout mywikifolder/key.pem -out mywik
|
||||
openssl x509 -req -days 365 -in mywikifolder/csr.pem -signkey mywikifolder/key.pem -out mywikifolder/server.crt
|
||||
tiddlywiki mywikifolder --listen username=joe password=bloggs tls-key=key.pem tls-cert=server.crt
|
||||
```
|
||||
|
||||
If using a [[tls-passphrase|WebServer Parameter: tls-passphrase]] to generate the certificate files, the commands would change as below:
|
||||
|
||||
* remove the `-nodes` flag, which specifies "no encryption"
|
||||
* replace `TLS_PASSPHRASE` in the `-passout` and `-passin` parameters in the below commands with your chosen string.
|
||||
|
||||
This is the simplest, but __least secure method,__ of passing a passphrase to the certificate utility. See [[this Stack Exchange anwser on openssl certificates|https://security.stackexchange.com/questions/106525/generate-csr-and-private-key-with-password-with-openssl]] and the [[openssl|https://www.openssl.org/docs/man1.0.2/man1/openssl.html]] and [[openssl-passphrase-options|https://www.openssl.org/docs/manmaster/man1/openssl-passphrase-options.html]] page in the openssl utility documentation.
|
||||
|
||||
```
|
||||
openssl req -newkey rsa:2048 -passout pass:TLS_PASSPHRASE -new -keyout mywikifolder/key.pem -out mywikifolder/csr.pem -passout pass:TLS_PASSPHRASE
|
||||
openssl x509 -req -days 365 -in mywikifolder/csr.pem -signkey mywikifolder/key.pem -out mywikifolder/server.crt -passin pass:TLS_PASSPHRASE
|
||||
tiddlywiki mywikifolder --listen username=joe password=bloggs tls-key=key.pem tls-cert=server.crt tls-passphrase=TLS_PASSPHRASE
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ In order to avoid denial of service attacks with malformed filters in the defaul
|
||||
To enable a particular filter, create a tiddler with the title "$:/config/Server/ExternalFilters/" concatenated with the filter text, and the text field set to "yes". For example, the TiddlyWeb plugin includes the following shadow tiddler to enable the filter that it requires:
|
||||
|
||||
```
|
||||
title: $:/config/Server/ExternalFilters/[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]]
|
||||
title: $:/config/Server/ExternalFilters/[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/library/sjcl.js]] -[[$:/core]]
|
||||
text: yes
|
||||
```
|
||||
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
created: 20180630194006239
|
||||
modified: 20180904174030250
|
||||
modified: 20211122004159427
|
||||
tags: WebServer
|
||||
title: WebServer Authorization
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
''Authorization'' is the process of determining which resources may be accessed by a particular user. It occurs after [[authentication|WebServer Authentication]] has determined the identity of the user. TiddlyWiki's WebServer implements a simple authorization scheme which permits independent control of who has read and write access to a wiki.
|
||||
''Authorization'' is the process of determining which resources may be accessed by a particular user. It occurs after [[authentication|WebServer Authentication]] has determined the identity of the user. TiddlyWiki's WebServer implements a simple authorization scheme which permits independent control of who has administrator access to the server, and read and write access to a wiki.
|
||||
|
||||
The WebServer parameters [[readers|WebServer Parameter: readers]] and [[writers|WebServer Parameter: writers]] each contain a comma separated list of //principals// (which is to say, either usernames or certain special tokens) which should have read or write access respectively.
|
||||
The WebServer parameters [[admin|WebServer Parameter: admin]], [[readers|WebServer Parameter: readers]] and [[writers|WebServer Parameter: writers]] each contain a comma separated list of //principals// (which is to say, either usernames or certain special tokens) which should have read or write access respectively.
|
||||
|
||||
The available special tokens are:
|
||||
|
||||
* ''(anon)'' - indicates all anonymous users
|
||||
* ''(authenticated)'' - indicates all authenticated users
|
||||
|
||||
!! Admin Functions
|
||||
|
||||
<<.tip"""The ''(anon)'' token is not valid for the [[admin|WebServer Parameter: admin]] parameter.""">>
|
||||
|
||||
At this time, no server functions are restricted to ''admin'' authorized users in the unmodified [[Tiddlywiki server|WebServer]]. Third party plugins can leverage this to restrict routes or commands to a subset of authorized users.
|
||||
|
||||
!! Read-only Mode
|
||||
|
||||
Read-only mode is engaged when the current user is not authorized to write to the current wiki.
|
||||
@@ -39,3 +45,9 @@ In the following example, read access is granted to all authenticated users, but
|
||||
```
|
||||
tiddlywiki mywikifolder --listen credentials=myusers.csv "readers=(authenticated)" writers=mary
|
||||
```
|
||||
|
||||
In the following example, read and write access is granted to all authenticated users, but only "mary" is granted admin access:
|
||||
|
||||
```
|
||||
tiddlywiki mywikifolder --listen credentials=myusers.csv "readers=(authenticated)" "writers=(authenticated)" admin=mary
|
||||
```
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
caption: admin
|
||||
created: 20211111015634164
|
||||
modified: 20211111023141767
|
||||
tags: [[WebServer Parameters]]
|
||||
title: WebServer Parameter: admin
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.2.2">> The [[web server configuration parameter|WebServer Parameters]] ''admin'' is used to specify the security principals with administrator access to the [[WebServer]]. Does not accept the ''(anon)'' special token. See [[WebServer Authorization]] for more details.
|
||||
@@ -0,0 +1,8 @@
|
||||
caption: required-plugins
|
||||
created: 20211226160733000
|
||||
modified: 20211226160754000
|
||||
tags: [[WebServer Parameters]]
|
||||
title: WebServer Parameter: required-plugins
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.2.2">> The [[web server configuration parameter|WebServer Parameters]] ''required-plugins'' is used to specify the plugins required to start the [[WebServer]]. It take a comma seperated list of plugin titles. The WebServer will issue a warnign in the console if the required plugins are not loaded. This parameter defaults to `$:/plugins/tiddlywiki/filesystem,$:/plugins/tiddlywiki/tiddlyweb`.
|
||||
@@ -0,0 +1,10 @@
|
||||
caption: tls-passphrase
|
||||
created: 20211111004416873
|
||||
modified: 20211111022120158
|
||||
tags: [[WebServer Parameters]]
|
||||
title: WebServer Parameter: tls-passphrase
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
<<.from-version "5.2.2">> The optional [[web server configuration parameter|WebServer Parameters]] ''tls-passphrase'' contains the "certificate passphrase", a string used to decrypt the certificate file used when running the web server under HTTPS.
|
||||
|
||||
See [[Using HTTPS]] for details.
|
||||
Reference in New Issue
Block a user