mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 18:17:20 +00:00
Refactor the filter mechanism
Long overdue rewrite to make it simpler, and break the filter operators out into individual modules.
This commit is contained in:
parent
6ada78daa2
commit
0cf5dc699e
@ -12,274 +12,6 @@ Adds tiddler filtering to the $tw.Wiki object.
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.filterTiddlers = function(filterString,currTiddlerTitle,tiddlerList) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,tiddlerList || this.tiddlers,currTiddlerTitle);
|
||||
};
|
||||
|
||||
/*
|
||||
Compiling a filter gives a JavaScript function that is invoked as `this.filter(source)`, where `source` is a hashmap of source tiddler titles (the values don't matter, so it is possible to use a store or a changes object). It returns an array of tiddler titles that satisfy the filter
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
var filter = this.parseFilter(filterString),
|
||||
output = [],
|
||||
t,operation,operationInfo,type,p,operator,operatorInfo,fn;
|
||||
output.push(this.filterFragments.prologue);
|
||||
for(t=0; t<filter.length; t++) {
|
||||
operation = filter[t];
|
||||
operationInfo = this.filterFragments.operation.prefix[operation.prefix || ""];
|
||||
output.push(operationInfo.prologue);
|
||||
type = "selector";
|
||||
if(operation.prefix === "+") {
|
||||
type = "filter";
|
||||
}
|
||||
for(p=0; p<operation.operators.length; p++) {
|
||||
operator = operation.operators[p];
|
||||
operatorInfo = this.operators[operator.operator];
|
||||
if(!operatorInfo) { // Check for it being a field operator
|
||||
operatorInfo = this.operators.field;
|
||||
}
|
||||
output.push(operatorInfo[type](operator));
|
||||
type = "filter";
|
||||
}
|
||||
output.push(operationInfo.epilogue);
|
||||
}
|
||||
output.push(this.filterFragments.epilogue);
|
||||
try {
|
||||
/*jslint evil: true */
|
||||
fn = eval(output.join("\n"));
|
||||
} catch(ex) {
|
||||
throw "Error in filter expression: " + ex;
|
||||
}
|
||||
return fn;
|
||||
};
|
||||
|
||||
exports.filterFragments = {
|
||||
prologue: "(function(source,currTiddlerTitle) {\nvar results = [], subResults, subResultsTemp, title, r, t;",
|
||||
epilogue: "return results;\n})",
|
||||
operation: {
|
||||
prefix: {
|
||||
"": {
|
||||
prologue: "subResults = [];",
|
||||
epilogue: "$tw.utils.pushTop(results,subResults);"
|
||||
},
|
||||
"+": {
|
||||
prologue: "subResults = results.slice(0);\nresults.splice(0,results.length);",
|
||||
epilogue: "$tw.utils.pushTop(results,subResults);"
|
||||
},
|
||||
"-": {
|
||||
prologue: "subResults = [];",
|
||||
epilogue: "$tw.utils.removeArrayEntries(results,subResults);"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.operators = {
|
||||
"title": { // Filter by title
|
||||
selector: function(operator) {
|
||||
if(operator.prefix === "!") {
|
||||
return "for(title in source) {if(title !== \"" + $tw.utils.stringify(operator.operand) + "\") {$tw.utils.pushTop(subResults,title);}}";
|
||||
} else {
|
||||
return "$tw.utils.pushTop(subResults,\"" + $tw.utils.stringify(operator.operand) + "\");";
|
||||
}
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "=";
|
||||
return "if(subResults.indexOf(\"" + $tw.utils.stringify(operator.operand) + "\") " + op + "== -1) {subResults = [\"" + $tw.utils.stringify(operator.operand) + "\"];} else {subResults = [];}";
|
||||
}
|
||||
},
|
||||
"prefix": { // Filter by title prefix
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "=";
|
||||
return "for(title in source) {if(title.substr(0," + operator.operand.length + ")" + op + "==\"" + $tw.utils.stringify(operator.operand) + "\") {$tw.utils.pushTop(subResults,title);}}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "=" : "!";
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(title.substr(0," + operator.operand.length + ")" + op + "==\"" + $tw.utils.stringify(operator.operand) + "\") {subResults.splice(r,1);}}";
|
||||
}
|
||||
},
|
||||
"is": { // Filter by status
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "";
|
||||
switch(operator.operand) {
|
||||
case "current":
|
||||
if(operator.prefix === "!") {
|
||||
return "for(title in source) {if(title !== currTiddlerTitle) {$tw.utils.pushTop(subResults,title);}}";
|
||||
} else {
|
||||
return "$tw.utils.pushTop(subResults,currTiddlerTitle);";
|
||||
}
|
||||
break;
|
||||
case "system":
|
||||
return "for(title in source) {if(" + op + "this.isSystemTiddler(title)) {$tw.utils.pushTop(subResults,title);}}";
|
||||
case "shadow":
|
||||
if(operator.prefix === "!") {
|
||||
return "for(title in source) {if(!this.isShadowTiddler(title)) {$tw.utils.pushTop(subResults,title);}}";
|
||||
} else {
|
||||
return "for(title in this.shadowTiddlers) {$tw.utils.pushTop(subResults,title);}";
|
||||
}
|
||||
case "missing":
|
||||
if(operator.prefix === "!") {
|
||||
return "for(title in source) {$tw.utils.pushTop(subResults,title);}";
|
||||
} else {
|
||||
return "var m = this.getMissingTitles(); for(t=0; t<m.length; t++) {$tw.utils.pushTop(subResults,m[t]);}";
|
||||
}
|
||||
case "orphan":
|
||||
if(operator.prefix === "!") {
|
||||
return "var m = this.getOrphanTitles(); for(title in source) {if(m.indexOf(title) === -1) {$tw.utils.pushTop(subResults,title);}}";
|
||||
} else {
|
||||
return "var m = this.getOrphanTitles(); for(t=0; t<m.length; t++) {$tw.utils.pushTop(subResults,m[t]);}";
|
||||
}
|
||||
default:
|
||||
throw "Unknown operand for 'is' filter operator";
|
||||
}
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "" : "!";
|
||||
switch(operator.operand) {
|
||||
case "current":
|
||||
if(operator.prefix === "!") {
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(subResults[r] === currTiddlerTitle) {subResults.splice(r,1);}}";
|
||||
} else {
|
||||
return "r = subResults.indexOf(currTiddlerTitle);\nif(r !== -1) {subResults = [currTiddlerTitle];} else {subResults = [];}";
|
||||
}
|
||||
break;
|
||||
case "system":
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(" + op + "this.isSystemTiddler(subResults[r])) {subResults.splice(r,1);}}";
|
||||
case "shadow":
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(" + op + "this.isShadowTiddler(subResults[r])) {subResults.splice(r,1);}}";
|
||||
case "missing":
|
||||
return "t = this.getMissingTitles(); for(r=subResults.length-1; r>=0; r--) {if(" + op + "!$tw.utils.hop(t,subResults[r])) {subResults.splice(r,1);}}";
|
||||
case "orphan":
|
||||
if(operator.prefix === "!") {
|
||||
return "t = this.getOrphanTitles(); for(r=subResults.length-1; r>=0; r--) {if(t.indexOf(subResults[r]) === -1) {subResults.splice(r,1);}}";
|
||||
} else {
|
||||
return "t = this.getOrphanTitles(); for(r=subResults.length-1; r>=0; r--) {if(t.indexOf(subResults[r]) !== -1) {subResults.splice(r,1);}}";
|
||||
}
|
||||
default:
|
||||
throw "Unknown operand for 'is' filter operator";
|
||||
}
|
||||
}
|
||||
},
|
||||
"tag": { // Filter by tag
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "";
|
||||
return "for(title in source) {if(" + op + "this.getTiddler(title).hasTag(\"" + $tw.utils.stringify(operator.operand) + "\")) {$tw.utils.pushTop(subResults,title);}}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "" : "!";
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(" + op + "this.getTiddler(subResults[r]).hasTag(\"" + $tw.utils.stringify(operator.operand) + "\")) {subResults.splice(r,1);}}";
|
||||
}
|
||||
},
|
||||
"tags": { // Return all tags used on selected tiddlers
|
||||
selector: function(operator) {
|
||||
return "for(title in source) {r = this.getTiddler(title); if(r && r.fields.tags) {$tw.utils.pushTop(subResults,r.fields.tags);}}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
return "subResultsTemp = subResults;\nsubResults = [];for(t=subResultsTemp.length-1; t>=0; t--) {r = this.getTiddler(subResultsTemp[t]); if(r && r.fields.tags) {$tw.utils.pushTop(subResults,r.fields.tags);}}";
|
||||
}
|
||||
},
|
||||
"tagging": { // Return all tiddlers tagged with any of the selected tags
|
||||
selector: function(operator) {
|
||||
return "for(title in source) {$tw.utils.pushTop(subResults,this.getTiddlersWithTag(title));}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
return "subResultsTemp = subResults;\nsubResults = [];for(t=subResultsTemp.length-1; t>=0; t--) {$tw.utils.pushTop(subResults,this.getTiddlersWithTag(subResultsTemp[t]));}";
|
||||
}
|
||||
},
|
||||
"links": { // Return outgoing links on selected tiddlers
|
||||
selector: function(operator) {
|
||||
return "for(title in source) {r = this.getTiddlerLinks(title); $tw.utils.pushTop(subResults,r);}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
return "subResultsTemp = subResults;\nsubResults = [];for(t=subResultsTemp.length-1; t>=0; t--) {r = this.getTiddlerLinks(subResultsTemp[t]); $tw.utils.pushTop(subResults,r);}";
|
||||
}
|
||||
},
|
||||
"backlinks": { // Return incoming links on selected tiddlers
|
||||
selector: function(operator) {
|
||||
return "for(title in source) {r = this.getTiddlerBacklinks(title); $tw.utils.pushTop(subResults,r);}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
return "subResultsTemp = subResults;\nsubResults = [];for(t=subResultsTemp.length-1; t>=0; t--) {r = this.getTiddlerBacklinks(subResultsTemp[t]); $tw.utils.pushTop(subResults,r);}";
|
||||
}
|
||||
},
|
||||
"has": { // Filter by presence of a particular field
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "=" : "!";
|
||||
return "for(title in source) {if(this.getTiddler(title).fields[\"" + $tw.utils.stringify(operator.operand) + "\"] " + op + "== undefined) {$tw.utils.pushTop(subResults,title);}}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "=";
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(this.getTiddler(subResults[r]).fields[\"" + $tw.utils.stringify(operator.operand) + "\"] " + op + "== undefined) {subResults.splice(r,1);}}";
|
||||
}
|
||||
},
|
||||
"sort": { // Sort selected tiddlers
|
||||
selector: function(operator) {
|
||||
throw "Cannot use sort operator at the start of a filter operation";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var desc = operator.prefix === "!" ? "true" : "false";
|
||||
return "this.sortTiddlers(subResults,\"" + $tw.utils.stringify(operator.operand) + "\"," + desc + ");";
|
||||
}
|
||||
}, // Case insensitive sort of selected tiddlers
|
||||
"sort-case-sensitive": {
|
||||
selector: function(operator) {
|
||||
throw "Cannot use sort operator at the start of a filter operation";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var desc = operator.prefix === "!" ? "true" : "false";
|
||||
return "this.sortTiddlers(subResults,\"" + $tw.utils.stringify(operator.operand) + "\"," + desc + ",true);";
|
||||
}
|
||||
},
|
||||
"limit": { // Limit number of members of selection
|
||||
selector: function(operator) {
|
||||
throw "Cannot use limit operator at the start of a filter operation";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var limit = parseInt(operator.operand,10),
|
||||
base = operator.prefix === "!" ? 0 : limit;
|
||||
return "if(subResults.length > " + limit + ") {subResults.splice(" + base + ",subResults.length-" + limit + ");}";
|
||||
}
|
||||
},
|
||||
"list": { // Select all tiddlers that are listed (or not listed) in the specified tiddler
|
||||
selector: function(operator) {
|
||||
if(operator.prefix === "!") {
|
||||
return "var list = this.getTiddlerList(\"" + $tw.utils.stringify(operator.operand) + "\");" +
|
||||
"for(title in source) {if(list.indexOf(title) === -1) {$tw.utils.pushTop(subResults,title);}}";
|
||||
} else {
|
||||
return "$tw.utils.pushTop(subResults,this.getTiddlerList(\"" + $tw.utils.stringify(operator.operand) + "\"));";
|
||||
}
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!==" : "===";
|
||||
return "var list = this.getTiddlerList(\"" + $tw.utils.stringify(operator.operand) + "\");" +
|
||||
"for(r=subResults.length-1; r>=0; r--) {if(list.indexOf(title) " + op + " -1) {subResults.splice(r,1);}}";
|
||||
}
|
||||
},
|
||||
"searchVia": { // Search for the string in the operand tiddler
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "true" : "false";
|
||||
return "var term = this.getTiddler(\"" + $tw.utils.stringify(operator.operand) + "\").fields.text;" +
|
||||
"$tw.utils.pushTop(subResults,this.search(term,{titles: source, invert: " + op + ", exclude: [\"" + $tw.utils.stringify(operator.operand) + "\"]}));";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "true" : "false";
|
||||
return "var term = this.getTiddler(\"" + $tw.utils.stringify(operator.operand) + "\").fields.text;" +
|
||||
"subResults = this.search(term,{titles: subResults, invert: " + op + ", exclude: [\"" + $tw.utils.stringify(operator.operand) + "\"]});";
|
||||
}
|
||||
},
|
||||
"field": { // Special handler for field comparisons
|
||||
selector: function(operator) {
|
||||
var op = operator.prefix === "!" ? "!" : "=";
|
||||
return "for(title in source) {if(this.getTiddler(title).fields[\"" + $tw.utils.stringify(operator.operator) + "\"] " + op + "== \"" + operator.operand + "\") {$tw.utils.pushTop(subResults,title);}}";
|
||||
},
|
||||
filter: function(operator) {
|
||||
var op = operator.prefix === "!" ? "=" : "!";
|
||||
return "for(r=subResults.length-1; r>=0; r--) {if(this.getTiddler(subResults[r]).fields[\"" + $tw.utils.stringify(operator.operator) + "\"] " + op + "== \"" + operator.operand + "\") {subResults.splice(r,1);}}";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Parses an operation within a filter string
|
||||
results: Array of array of operator nodes into which results should be inserted
|
||||
@ -376,4 +108,70 @@ exports.parseFilter = function(filterString) {
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.getFilterOperators = function() {
|
||||
if(!this.filterOperators) {
|
||||
$tw.Wiki.prototype.filterOperators = {};
|
||||
$tw.modules.applyMethods("filteroperator",this.filterOperators);
|
||||
}
|
||||
return this.filterOperators;
|
||||
};
|
||||
|
||||
exports.filterTiddlers = function(filterString,currTiddlerTitle,tiddlerList) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,tiddlerList || this.tiddlers,currTiddlerTitle);
|
||||
};
|
||||
|
||||
exports.compileFilter = function(filterString) {
|
||||
var filterParseTree = this.parseFilter(filterString);
|
||||
// Get the hashmap of filter operator functions
|
||||
var filterOperators = this.getFilterOperators();
|
||||
// Assemble array of functions, one for each operation
|
||||
var operationFunctions = [];
|
||||
// Step through the operations
|
||||
var self = this;
|
||||
$tw.utils.each(filterParseTree,function(operation) {
|
||||
// Create a function for the chain of operators in the operation
|
||||
var operationSubFunction = function(source,currTiddlerTitle) {
|
||||
var accumulator = source,
|
||||
results = [];
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operatorFunction = filterOperators[operator.operator] || filterOperators.field || function(source,operator,operations) {
|
||||
return ["Filter Error: unknown operator '" + operator.operator + "'"];
|
||||
};
|
||||
results = operatorFunction(accumulator,operator,{wiki: self, currTiddlerTitle: currTiddlerTitle});
|
||||
accumulator = results;
|
||||
});
|
||||
return results;
|
||||
};
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
|
||||
};
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
$tw.utils.removeArrayEntries(results,operationSubFunction(source,currTiddlerTitle));
|
||||
};
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return function(results,source,currTiddlerTitle) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
source = results.slice(0);
|
||||
results.splice(0,results.length);
|
||||
$tw.utils.pushTop(results,operationSubFunction(source,currTiddlerTitle));
|
||||
};
|
||||
}
|
||||
})());
|
||||
});
|
||||
// Return a function that applies the operations to a source array/hashmap of tiddler titles
|
||||
return function(source,currTiddlerTitle) {
|
||||
var results = [];
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,currTiddlerTitle);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
};
|
||||
|
||||
})();
|
||||
|
37
core/modules/filters/backlinks.js
Normal file
37
core/modules/filters/backlinks.js
Normal file
@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/backlinks.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning all the backlinks from a tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerBacklinks(title));
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
46
core/modules/filters/field.js
Normal file
46
core/modules/filters/field.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/field.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for comparing fields for equality
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.field = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.fields[operator.operator] === operator.operand;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
46
core/modules/filters/has.js
Normal file
46
core/modules/filters/has.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/has.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking if a tiddler has the specified field
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.has = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = $tw.utils.hop(tiddler.fields,operator.operand);
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
39
core/modules/filters/is.js
Normal file
39
core/modules/filters/is.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking tiddler properties
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var isFilterOperators;
|
||||
|
||||
function getIsFilterOperators() {
|
||||
if(!isFilterOperators) {
|
||||
isFilterOperators = {};
|
||||
$tw.modules.applyMethods("isfilteroperator",isFilterOperators);
|
||||
}
|
||||
return isFilterOperators;
|
||||
};
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.is = function(source,operator,options) {
|
||||
// Dispatch to the correct isfilteroperator
|
||||
var isFilterOperators = getIsFilterOperators();
|
||||
var isFilterOperator = isFilterOperators[operator.operand];
|
||||
if(isFilterOperator) {
|
||||
return isFilterOperator(source,operator.prefix,options);
|
||||
} else {
|
||||
return ["Filter Error: Unknown operand for the 'is' filter operator"];
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
49
core/modules/filters/is/current.js
Normal file
49
core/modules/filters/is/current.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/current.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[current]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
if(title !== options.currTiddlerTitle) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
if(prefix === "!") {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
if(source.indexOf(options.currTiddlerTitle) !== -1) {
|
||||
results.push(options.currTiddlerTitle);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(prefix === "!") {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
results.push(options.currTiddlerTitle);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
48
core/modules/filters/is/missing.js
Normal file
48
core/modules/filters/is/missing.js
Normal file
@ -0,0 +1,48 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/missing.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[missing]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.missing = function(source,prefix,options) {
|
||||
var results = [],
|
||||
missingTitles;
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
missingTitles = options.wiki.getMissingTitles();
|
||||
$tw.utils.each(source,function(title) {
|
||||
var match = missingTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if(prefix !== "!") {
|
||||
missingTitles = options.wiki.getMissingTitles();
|
||||
$tw.utils.each(missingTitles,function(title) {
|
||||
results.push(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
46
core/modules/filters/is/orphan.js
Normal file
46
core/modules/filters/is/orphan.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/orphan.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[orphan]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.orphan = function(source,prefix,options) {
|
||||
var results = [],
|
||||
orphanTitles = options.wiki.getOrphanTitles();
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
var match = orphanTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
var match = orphanTitles.indexOf(title) !== -1;
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
49
core/modules/filters/is/shadow.js
Normal file
49
core/modules/filters/is/shadow.js
Normal file
@ -0,0 +1,49 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/shadow.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[shadow]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.shadow = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.isShadowTiddler(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
if(prefix !== "!") {
|
||||
$tw.utils.each(options.wiki.shadowTiddlers,function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
43
core/modules/filters/is/system.js
Normal file
43
core/modules/filters/is/system.js
Normal file
@ -0,0 +1,43 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/is/system.js
|
||||
type: application/javascript
|
||||
module-type: isfilteroperator
|
||||
|
||||
Filter function for [is[system]]
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.system = function(source,prefix,options) {
|
||||
var results = [];
|
||||
// Function to check a tiddler
|
||||
function checkTiddler(title) {
|
||||
var match = options.wiki.isSystemTiddler(title);
|
||||
if(prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
38
core/modules/filters/limit.js
Normal file
38
core/modules/filters/limit.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/limit.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for chopping the results to a specified maximum number of entries
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.limit = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Convert to an array if necessary
|
||||
if(!$tw.utils.isArray(source)) {
|
||||
var copy = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
copy.push(title);
|
||||
});
|
||||
source = copy;
|
||||
}
|
||||
// Slice the array if necessary
|
||||
var limit = Math.min(source.length,parseInt(operator.operand,10));
|
||||
if(operator.prefix === "!") {
|
||||
results = source.slice(source.length - limit,limit);
|
||||
} else {
|
||||
results = source.slice(0,limit);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
37
core/modules/filters/links.js
Normal file
37
core/modules/filters/links.js
Normal file
@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/links.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning all the links from a tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.links = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlerLinks(title));
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
47
core/modules/filters/list.js
Normal file
47
core/modules/filters/list.js
Normal file
@ -0,0 +1,47 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/list.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the tiddlers whose title is listed in the operand tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.list = function(source,operator,options) {
|
||||
var results = [],
|
||||
list = options.wiki.getTiddlerList(operator.operand);
|
||||
function checkTiddler(title) {
|
||||
var match = list.indexOf(title) !== -1;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
if(operator.prefix !== "!") {
|
||||
results = list;
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
46
core/modules/filters/prefix.js
Normal file
46
core/modules/filters/prefix.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/prefix.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking if a title starts with a prefix
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.prefix = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.fields.title.substr(0,operator.operand.length) === operator.operand;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
28
core/modules/filters/searchVia.js
Normal file
28
core/modules/filters/searchVia.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/searchVia.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for searching for the text in the operand tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.searchVia = function(source,operator,options) {
|
||||
var term = options.wiki.getTiddlerText(operator.operand,""),
|
||||
invert = operator.prefix === "!";
|
||||
return options.wiki.search(term,{
|
||||
titles: source,
|
||||
invert: invert,
|
||||
exclude: [operator.operand]
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
32
core/modules/filters/sort.js
Normal file
32
core/modules/filters/sort.js
Normal file
@ -0,0 +1,32 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/sort.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for sorting
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.sort = function(source,operator,options) {
|
||||
var results;
|
||||
if($tw.utils.isArray(source)) {
|
||||
results = source;
|
||||
} else {
|
||||
results = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!");
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
32
core/modules/filters/sortcs.js
Normal file
32
core/modules/filters/sortcs.js
Normal file
@ -0,0 +1,32 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/sortcs.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for case-sensitive sorting
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
var results;
|
||||
if($tw.utils.isArray(source)) {
|
||||
results = source;
|
||||
} else {
|
||||
results = [];
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
results.push(title);
|
||||
});
|
||||
}
|
||||
options.wiki.sortTiddlers(results,operator.operand,operator.prefix === "!",true);
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
46
core/modules/filters/tag.js
Normal file
46
core/modules/filters/tag.js
Normal file
@ -0,0 +1,46 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/tag.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for checking for the presence of a tag
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tag = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.hasTag(operator.operand);
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
37
core/modules/filters/tagging.js
Normal file
37
core/modules/filters/tagging.js
Normal file
@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/tagging.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning all tiddlers that are tagged with the selected tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tagging = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
$tw.utils.pushTop(results,options.wiki.getTiddlersWithTag(title));
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
40
core/modules/filters/tags.js
Normal file
40
core/modules/filters/tags.js
Normal file
@ -0,0 +1,40 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/tags.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning all tiddlers tagging the selected tiddlers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tags = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler && tiddler.fields.tags) {
|
||||
$tw.utils.pushTop(results,tiddler.fields.tags);
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
53
core/modules/filters/title.js
Normal file
53
core/modules/filters/title.js
Normal file
@ -0,0 +1,53 @@
|
||||
/*\
|
||||
title: $:/core/modules/filters/title.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for comparing title fields for equality
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.title = function(source,operator,options) {
|
||||
var results = [];
|
||||
// Function to check an individual title
|
||||
function checkTiddler(title) {
|
||||
var tiddler = options.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var match = tiddler.fields[operator.operator] === operator.operand;
|
||||
if(operator.prefix === "!") {
|
||||
match = !match;
|
||||
}
|
||||
if(match) {
|
||||
results.push(title);
|
||||
}
|
||||
}
|
||||
};
|
||||
// Iterate through the source tiddlers
|
||||
if($tw.utils.isArray(source)) {
|
||||
$tw.utils.each(source,function(title) {
|
||||
checkTiddler(title);
|
||||
});
|
||||
} else {
|
||||
// If we're filtering a hashmap we change the behaviour to pass through missing tiddlers
|
||||
if(operator.prefix !== "!") {
|
||||
results.push(operator.operand);
|
||||
} else {
|
||||
$tw.utils.each(source,function(element,title) {
|
||||
if(title !== operator.operand) {
|
||||
checkTiddler(title);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
})();
|
181
editions/test/tiddlers/tests/test-filters.js
Normal file
181
editions/test/tiddlers/tests/test-filters.js
Normal file
@ -0,0 +1,181 @@
|
||||
/*\
|
||||
title: test-filters.js
|
||||
type: application/javascript
|
||||
tags: [[$:/tags/test-spec]]
|
||||
|
||||
Tests the filtering mechanism.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
describe("Filter tests", function() {
|
||||
|
||||
// Create a wiki
|
||||
var wiki = new $tw.Wiki();
|
||||
|
||||
// Some helpers
|
||||
var addShadowTiddler = function(fields) {
|
||||
var tiddler = new $tw.Tiddler(fields);
|
||||
wiki.shadowTiddlers[tiddler.fields.title] = {tiddler: tiddler};
|
||||
};
|
||||
|
||||
// Add a few tiddlers
|
||||
wiki.addTiddler({
|
||||
title: "TiddlerOne",
|
||||
text: "The quick brown fox in $:/TiddlerTwo",
|
||||
tags: ["one"],
|
||||
modifier: "JoeBloggs"});
|
||||
wiki.addTiddler({
|
||||
title: "$:/TiddlerTwo",
|
||||
text: "The rain in Spain\nfalls mainly on the plain and [[a fourth tiddler]]",
|
||||
tags: ["two"]});
|
||||
wiki.addTiddler({
|
||||
title: "Tiddler Three",
|
||||
text: "The speed of sound in light\n\nThere is no TiddlerZero but TiddlerSix",
|
||||
tags: ["one","two"]});
|
||||
wiki.addTiddler({
|
||||
title: "a fourth tiddler",
|
||||
text: "The quality of mercy is not drained by [[Tiddler Three]]",
|
||||
tags: []});
|
||||
// And some shadows
|
||||
addShadowTiddler({
|
||||
title: "$:/TiddlerFive",
|
||||
text: "Everything in federation",
|
||||
tags: ["two"]});
|
||||
addShadowTiddler({
|
||||
title: "TiddlerSix",
|
||||
text: "Missing inaction from TiddlerOne",
|
||||
tags: []});
|
||||
addShadowTiddler({
|
||||
title: "TiddlerSeventh",
|
||||
text: "TiddlerOne\nTiddler Three\na fourth tiddler\nMissingTiddler",
|
||||
tags: []});
|
||||
addShadowTiddler({
|
||||
title: "Tiddler8",
|
||||
text: "Tidd",
|
||||
tags: []});
|
||||
|
||||
// Our tests
|
||||
|
||||
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("TiddlerOne,$:/TiddlerTwo,a fourth tiddler");
|
||||
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("$:/TiddlerTwo,Tiddler Three,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[!is[system]!modifier[JoeBloggs]]").join(",")).toBe("Tiddler Three,a fourth tiddler");
|
||||
});
|
||||
|
||||
it("should handle the prefix operator", function() {
|
||||
expect(wiki.filterTiddlers("[prefix[Tiddler]]").join(",")).toBe("TiddlerOne,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[prefix[nothing]]").join(",")).toBe("");
|
||||
});
|
||||
|
||||
it("should handle the sort and sortcs operators", function() {
|
||||
expect(wiki.filterTiddlers("[sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!sort[title]]").join(",")).toBe("TiddlerOne,Tiddler Three,a fourth tiddler,$:/TiddlerTwo");
|
||||
expect(wiki.filterTiddlers("[sortcs[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three,TiddlerOne,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[!sortcs[title]]").join(",")).toBe("a fourth tiddler,TiddlerOne,Tiddler Three,$:/TiddlerTwo");
|
||||
});
|
||||
|
||||
it("should handle the tag operator", function() {
|
||||
expect(wiki.filterTiddlers("[tag[one]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!tag[one]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[prefix[Tidd]tag[one]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!is[shadow]tag[two]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[is[shadow]tag[two]sort[title]]").join(",")).toBe("$:/TiddlerFive");
|
||||
});
|
||||
|
||||
it("should handle the tags operator", function() {
|
||||
expect(wiki.filterTiddlers("[tags[]sort[title]]").join(",")).toBe("one,two");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]tags[]sort[title]]").join(",")).toBe("one");
|
||||
});
|
||||
|
||||
it("should handle the tagging operator", function() {
|
||||
expect(wiki.filterTiddlers("[[one]tagging[]sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[[two]tagging[]sort[title]]").join(",")).toBe("$:/TiddlerTwo,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[is[current]tagging[]sort[title]]","one").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the links operator", function() {
|
||||
expect(wiki.filterTiddlers("[!is[shadow]links[]sort[title]]").join(",")).toBe("a fourth tiddler,Tiddler Three,TiddlerSix,TiddlerTwo,TiddlerZero");
|
||||
expect(wiki.filterTiddlers("[is[shadow]links[]sort[title]]").join(",")).toBe("MissingTiddler,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the backlinks operator", function() {
|
||||
expect(wiki.filterTiddlers("[!is[shadow]backlinks[]sort[title]]").join(",")).toBe("a fourth tiddler");
|
||||
expect(wiki.filterTiddlers("[is[shadow]backlinks[]sort[title]]").join(",")).toBe("Tiddler Three");
|
||||
});
|
||||
|
||||
it("should handle the has operator", function() {
|
||||
expect(wiki.filterTiddlers("[has[modifier]sort[title]]").join(",")).toBe("TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!has[modifier]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three");
|
||||
});
|
||||
|
||||
it("should handle the limit operator", function() {
|
||||
expect(wiki.filterTiddlers("[!is[system]sort[title]limit[2]]").join(",")).toBe("a fourth tiddler,Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[prefix[Tid]sort[title]limit[1]]").join(",")).toBe("Tiddler Three");
|
||||
});
|
||||
|
||||
it("should handle the list operator", function() {
|
||||
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("Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the searchVia operator", function() {
|
||||
expect(wiki.filterTiddlers("[searchVia[Tiddler8]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
describe("testing the is operator",function() {
|
||||
|
||||
it("should handle the '[is[current]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[current]]","Tiddler Three").join(",")).toBe("Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[[Tiddler Three]is[current]]","Tiddler Three").join(",")).toBe("Tiddler Three");
|
||||
expect(wiki.filterTiddlers("[[$:/TiddlerTwo]is[current]]","Tiddler Three").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[!is[current]sort[title]]","Tiddler Three").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the '[is[system]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[system]]").join(",")).toBe("$:/TiddlerTwo");
|
||||
expect(wiki.filterTiddlers("[!is[system]sort[title]]").join(",")).toBe("a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the '[is[shadow]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[shadow]sort[title]]").join(",")).toBe("$:/TiddlerFive,Tiddler8,TiddlerSeventh,TiddlerSix");
|
||||
expect(wiki.filterTiddlers("[!is[shadow]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the '[is[missing]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[missing]]").join(",")).toBe("TiddlerZero,TiddlerSix,TiddlerTwo");
|
||||
expect(wiki.filterTiddlers("[!is[missing]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,Tiddler Three,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[[TiddlerOne]is[missing]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[[TiddlerZero]is[missing]]").join(",")).toBe("TiddlerZero");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]is[missing]]").join(",")).toBe("");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]!is[missing]sort[title]]").join(",")).toBe("$:/TiddlerTwo,a fourth tiddler,TiddlerOne");
|
||||
});
|
||||
|
||||
it("should handle the '[is[orphan]]' operator", function() {
|
||||
expect(wiki.filterTiddlers("[is[orphan]sort[title]]").join(",")).toBe("a fourth tiddler,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!is[orphan]]").join(",")).toBe("$:/TiddlerTwo,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,TiddlerOne");
|
||||
expect(wiki.filterTiddlers("[!title[Tiddler Three]!is[orphan]]").join(",")).toBe("$:/TiddlerTwo");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("should handle the operand prefixes", function() {
|
||||
expect(wiki.filterTiddlers("[prefix[Tiddler]] +[sort[title]]").join(",")).toBe("Tiddler Three,TiddlerOne");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
})();
|
@ -46,11 +46,11 @@ Welcome to TiddlyWiki created by Jeremy Ruston; Copyright © 2004-2007 Jerem
|
||||
<div id="contentWrapper"></div>
|
||||
<div id="contentStash"></div>
|
||||
<div id="shadowArea">
|
||||
{{{ [prefix[{shadow}]] +[sort-case-sensitive[title]] ||$:/core/templates/html-div-tiddler-remove-prefix}}}
|
||||
{{{ [prefix[{shadow}]] +[sortcs[title]] ||$:/core/templates/html-div-tiddler-remove-prefix}}}
|
||||
</div>
|
||||
<!--POST-SHADOWAREA-->
|
||||
<div id="storeArea">
|
||||
{{{ [prefix[{tiddler}]] +[sort-case-sensitive[title]] ||$:/core/templates/html-div-tiddler-remove-prefix}}}
|
||||
{{{ [prefix[{tiddler}]] +[sortcs[title]] ||$:/core/templates/html-div-tiddler-remove-prefix}}}
|
||||
{{{ [prefix[{plugin}]] ||$:/core/templates/plain-text-tiddler}}}
|
||||
{{{ [prefix[{posttiddlers}]] ||$:/core/templates/plain-text-tiddler}}}
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@ A filter string consists of one or more runs of filter operators that each look
|
||||
* ''is'': tests whether a tiddler is a member of the system defined set named in the operand (see below)
|
||||
* ''has'': tests whether a tiddler has the field specified in the operand
|
||||
* ''sort'': sorts the tiddlers by the field specified in the operand
|
||||
* ''sort-case-sensitive'': a case sensitive sort of the current tiddlers by the field specified in the operand
|
||||
* ''sortcs'': a case sensitive sort of the current tiddlers by the field specified in the operand
|
||||
* ''prefix'': tests whether a tiddlers title starts with the prefix specified in the operand
|
||||
* ''limit'': limits the number of subresults to the integer specified in the operand
|
||||
* ''tag'': tests whether a given tag is (`[tag[mytag]]`) or is not (`[!tag[mytag]]`) present on the tiddler
|
||||
|
Loading…
Reference in New Issue
Block a user