1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-21 01:19:53 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
Jeremy Ruston
d8b0e041b6 Initial commit 2026-02-19 12:45:27 +00:00
492 changed files with 4438 additions and 8508 deletions

View File

@@ -15,40 +15,40 @@ var fs = require("fs"),
{ optimize } = require("svgo"),
config = {
plugins: [
"cleanupAttrs",
"removeDoctype",
"removeXMLProcInst",
"removeComments",
"removeMetadata",
"removeTitle",
"removeDesc",
"removeUselessDefs",
"removeEditorsNSData",
"removeEmptyAttrs",
"removeHiddenElems",
"removeEmptyText",
"removeEmptyContainers",
'cleanupAttrs',
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeTitle',
'removeDesc',
'removeUselessDefs',
'removeEditorsNSData',
'removeEmptyAttrs',
'removeHiddenElems',
'removeEmptyText',
'removeEmptyContainers',
// 'removeViewBox',
"cleanupEnableBackground",
"convertStyleToAttrs",
"convertColors",
"convertPathData",
"convertTransform",
"removeUnknownsAndDefaults",
"removeNonInheritableGroupAttrs",
"removeUselessStrokeAndFill",
"removeUnusedNS",
"cleanupIDs",
"cleanupNumericValues",
"moveElemsAttrsToGroup",
"moveGroupAttrsToElems",
"collapseGroups",
'cleanupEnableBackground',
'convertStyleToAttrs',
'convertColors',
'convertPathData',
'convertTransform',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeUnusedNS',
'cleanupIDs',
'cleanupNumericValues',
'moveElemsAttrsToGroup',
'moveGroupAttrsToElems',
'collapseGroups',
// 'removeRasterImages',
"mergePaths",
"convertShapeToPath",
"sortAttrs",
'mergePaths',
'convertShapeToPath',
'sortAttrs',
//'removeDimensions',
{name: "removeAttrs", params: { attrs: "(stroke|fill)" } }
{name: 'removeAttrs', params: { attrs: '(stroke|fill)' } }
]
};
@@ -72,7 +72,7 @@ files.forEach(function(filename) {
var newSVG = header.join("\n") + "\n\n" + result.data.replace("&lt;&lt;now &quot;DD&quot;&gt;&gt;","<<now \"DD\">>");
fs.writeFileSync(filepath,newSVG);
} else {
console.log("Error " + err + " with " + filename);
console.log("Error " + err + " with " + filename)
process.exit();
};
}

View File

@@ -12,6 +12,8 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
var _boot = (function($tw) {
/*jslint node: true, browser: true */
/*global modules: false, $tw: false */
"use strict";
// Include bootprefix if we're not given module data
@@ -35,7 +37,7 @@ if($tw.node) {
$tw.boot.log = function(str) {
$tw.boot.logMessages = $tw.boot.logMessages || [];
$tw.boot.logMessages.push(str);
};
}
/*
Check if an object has a property
@@ -45,7 +47,7 @@ $tw.utils.hop = function(object,property) {
};
/** @deprecated Use Array.isArray instead */
$tw.utils.isArray = (value) => Array.isArray(value);
$tw.utils.isArray = value => Array.isArray(value);
/*
Check if an array is equal by value and by reference.
@@ -125,7 +127,7 @@ $tw.utils.pushTop = function(array,value) {
};
/** @deprecated Use instanceof Date instead */
$tw.utils.isDate = (value) => value instanceof Date;
$tw.utils.isDate = value => value instanceof Date;
/** @deprecated Use array iterative methods instead */
$tw.utils.each = function(object,callback) {
@@ -136,7 +138,7 @@ $tw.utils.each = function(object,callback) {
return next !== false;
});
} else {
Object.entries(object).every((entry) => {
Object.entries(object).every(entry => {
const next = callback(entry[1], entry[0], object);
return next !== false;
});
@@ -563,7 +565,7 @@ using a lowercase extension only.
*/
$tw.utils.getFileExtensionInfo = function(ext) {
return ext ? $tw.config.fileExtensionInfo[ext.toLowerCase()] : null;
};
}
/*
Given an extension, get the correct encoding for that file.
@@ -586,7 +588,7 @@ var globalCheck =[
" delete Object.prototype.__temp__;",
" }",
" delete Object.prototype.__temp__;",
].join("\n");
].join('\n');
/*
Run code globally with specified context variables in scope
@@ -614,7 +616,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
fn = Function("return " + code + "\n\n//# sourceURL=" + filename)(); // See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
} else {
if(sandbox){
fn = vm.runInContext(code,sandbox,filename);
fn = vm.runInContext(code,sandbox,filename)
} else {
fn = vm.runInThisContext(code,filename);
}
@@ -725,7 +727,7 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
var self = this;
form.addEventListener("submit",function(event) {
// Collect the form data
var data = {};
var data = {},t;
$tw.utils.each(form.elements,function(element) {
if(element.name && element.value) {
data[element.name] = element.value;
@@ -771,7 +773,7 @@ $tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
promptInfo.form.parentNode.removeChild(promptInfo.form);
this.setWrapperDisplay();
}
};
}
/*
Crypto helper object for encrypted content. It maintains the password text in a closure, and provides methods to change
@@ -810,7 +812,7 @@ $tw.utils.Crypto = function() {
};
this.hasPassword = function() {
return !!currentPassword;
};
}
this.encrypt = function(text,password) {
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
@@ -828,7 +830,7 @@ Execute the module named 'moduleName'. The name can optionally be relative to th
$tw.modules.execute = function(moduleName,moduleRoot) {
var name = moduleName;
if(moduleName.charAt(0) === ".") {
name = $tw.utils.resolvePath(moduleName,moduleRoot);
name = $tw.utils.resolvePath(moduleName,moduleRoot)
}
if(!$tw.modules.titles[name]) {
if($tw.modules.titles[name + ".js"]) {
@@ -889,6 +891,7 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
if(!moduleInfo) {
// We could not find the module on this path
// Try to defer to browserify etc, or node
var deferredModule;
if($tw.browser) {
if(window.require) {
try {
@@ -1143,7 +1146,8 @@ enableIndexers - Array of indexer names to enable, or null to use all available
*/
$tw.Wiki = function(options) {
options = options || {};
var tiddlers = Object.create(null), // Hashmap of tiddlers
var self = this,
tiddlers = Object.create(null), // Hashmap of tiddlers
tiddlerTitles = null, // Array of tiddler titles
getTiddlerTitles = function() {
if(!tiddlerTitles) {
@@ -1197,7 +1201,7 @@ $tw.Wiki = function(options) {
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
};
}
// Save the new tiddler
tiddlers[title] = tiddler;
// Check we've got the title
@@ -1207,7 +1211,7 @@ $tw.Wiki = function(options) {
tiddler: tiddler,
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
};
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
@@ -1232,7 +1236,7 @@ $tw.Wiki = function(options) {
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
}
};
}
// Delete the tiddler
delete tiddlers[title];
// Delete it from the list of titles
@@ -1247,7 +1251,7 @@ $tw.Wiki = function(options) {
tiddler: this.getTiddler(title),
shadow: this.isShadowTiddler(title),
exists: this.tiddlerExists(title)
};
}
// Update indexes
this.clearCache(title);
this.clearGlobalCache();
@@ -1435,7 +1439,8 @@ $tw.Wiki = function(options) {
// Unregister the plugin tiddlers of a particular type, or null/undefined for any type, optionally restricting unregistering to an array of tiddler titles. Returns an array of the titles affected
this.unregisterPluginTiddlers = function(pluginType,titles) {
var unregisteredTitles = [];
var self = this,
unregisteredTitles = [];
// Remove any previous registered plugins of this type
for(var t=pluginTiddlers.length-1; t>=0; t--) {
var tiddler = pluginTiddlers[t];
@@ -1449,15 +1454,16 @@ $tw.Wiki = function(options) {
// Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
this.unpackPluginTiddlers = function() {
var self = this;
// Sort the plugin titles by the `plugin-priority` field, if this field is missing, default to 1
pluginTiddlers.sort(function(a, b) {
var priorityA = "plugin-priority" in a.fields ? a.fields["plugin-priority"] : 1;
var priorityB = "plugin-priority" in b.fields ? b.fields["plugin-priority"] : 1;
if(priorityA !== priorityB) {
if (priorityA !== priorityB) {
return priorityA - priorityB;
} else if(a.fields.title < b.fields.title) {
} else if (a.fields.title < b.fields.title) {
return -1;
} else if(a.fields.title === b.fields.title) {
} else if (a.fields.title === b.fields.title) {
return 0;
} else {
return +1;
@@ -1564,7 +1570,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
// Assemble a report tiddler
var titleReportTiddler = "TiddlyWiki Safe Mode",
report = [];
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:");
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:")
// Delete the overrides
overrides.forEach(function(title) {
var tiddler = self.getTiddler(title),
@@ -1573,7 +1579,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
report.push("* [[" + title + "|" + newTitle + "]]");
});
report.push();
report.push()
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
// Set $:/DefaultTiddlers to point to our report
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
@@ -2007,7 +2013,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
break;
case "filepath":
value = path.relative(rootPath, filename).split(path.sep).join("/");
value = path.relative(rootPath, filename).split(path.sep).join('/');
break;
case "filename":
value = path.basename(filename);
@@ -2060,7 +2066,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
}
});
return arrayOfFiles;
};
}
// Process the listed tiddlers
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
if(tidInfo.prefix && tidInfo.suffix) {
@@ -2169,7 +2175,7 @@ Returns the path of the plugin folder
$tw.findLibraryItem = function(name,paths) {
var pathIndex = 0;
do {
var pluginPath = path.resolve(paths[pathIndex],"./" + name);
var pluginPath = path.resolve(paths[pathIndex],"./" + name)
if(fs.existsSync(pluginPath) && fs.statSync(pluginPath).isDirectory()) {
return pluginPath;
}
@@ -2528,7 +2534,7 @@ $tw.boot.initStartup = function(options) {
}
});
return result;
};
}
}
};
$tw.boot.loadStartup = function(options){
@@ -2545,7 +2551,7 @@ $tw.boot.loadStartup = function(options){
}
// Give hooks a chance to modify the store
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
};
}
$tw.boot.execStartup = function(options){
// Unpack plugin tiddlers
$tw.wiki.readPluginInfo();
@@ -2575,7 +2581,7 @@ $tw.boot.execStartup = function(options){
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
// Repeatedly execute the next eligible task
$tw.boot.executeNextStartupTask(options.callback);
};
}
/*
Startup TiddlyWiki
*/
@@ -2594,7 +2600,7 @@ $tw.addUnloadTask = function(task) {
if($tw.unloadTasks.indexOf(task) === -1) {
$tw.unloadTasks.push(task);
}
};
}
/*
Execute the remaining eligible startup tasks
@@ -2641,7 +2647,7 @@ $tw.boot.executeNextStartupTask = function(callback) {
}
taskIndex++;
}
if(typeof callback === "function") {
if(typeof callback === 'function') {
callback();
}
return false;

View File

@@ -103,7 +103,7 @@ Commander.prototype.executeNextCommand = function() {
c = new command.Command(params,this);
err = c.execute();
if(err && typeof err.then === "function") {
err.then((e) => { e ? this.callback(e) : this.executeNextCommand(); });
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
} else if(err) {
this.callback(err);
} else {
@@ -120,7 +120,7 @@ Commander.prototype.executeNextCommand = function() {
});
err = c.execute();
if(err && typeof err.then === "function") {
err.then((e) => { if(e) this.callback(e); });
err.then(e => { if(e) this.callback(e); });
} else if(err) {
this.callback(err);
}

View File

@@ -25,7 +25,7 @@ Command.prototype.execute = function() {
if(!filter) {
return "No filter specified";
}
var commands = this.commander.wiki.filterTiddlers(filter);
var commands = this.commander.wiki.filterTiddlers(filter)
if(commands.length === 0) {
return "No tiddlers found for filter '" + filter + "'";
}

View File

@@ -24,7 +24,8 @@ Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filter";
}
var wiki = this.commander.wiki,
var self = this,
wiki = this.commander.wiki,
filter = this.params[0],
tiddlers = wiki.filterTiddlers(filter);
$tw.utils.each(tiddlers,function(title) {

View File

@@ -66,7 +66,7 @@ Command.prototype.fetchFiles = function(options) {
// Get the list of URLs
var urls;
if(options.url) {
urls = [options.url];
urls = [options.url]
} else if(options.urlFilter) {
urls = this.commander.wiki.filterTiddlers(options.urlFilter);
} else {
@@ -96,30 +96,30 @@ Command.prototype.fetchFile = function(url,options,callback,redirectCount) {
var self = this,
lib = url.substr(0,8) === "https://" ? require("https") : require("http");
lib.get(url).on("response",function(response) {
var type = (response.headers["content-type"] || "").split(";")[0],
data = [];
self.commander.write("Reading " + url + ": ");
response.on("data",function(chunk) {
data.push(chunk);
self.commander.write(".");
});
response.on("end",function() {
self.commander.write("\n");
if(response.statusCode === 200) {
self.processBody(Buffer.concat(data),type,options,url);
callback(null);
} else {
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
} else {
return callback("Error " + response.statusCode + " retrieving " + url);
}
}
});
response.on("error",function(e) {
var type = (response.headers["content-type"] || "").split(";")[0],
data = [];
self.commander.write("Reading " + url + ": ");
response.on("data",function(chunk) {
data.push(chunk);
self.commander.write(".");
});
response.on("end",function() {
self.commander.write("\n");
if(response.statusCode === 200) {
self.processBody(Buffer.concat(data),type,options,url);
callback(null);
} else {
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
} else {
return callback("Error " + response.statusCode + " retrieving " + url)
}
}
});
response.on("error",function(e) {
console.log("Error on GET request: " + e);
callback(e);
});
});
});
return null;
};
@@ -153,18 +153,18 @@ Command.prototype.processBody = function(body,type,options,url) {
if(options.transformFilter) {
var transformedTitle = (incomingWiki.filterTiddlers(options.transformFilter,null,self.commander.wiki.makeTiddlerIterator([title])) || [""])[0];
if(transformedTitle) {
self.commander.log("Importing " + title + " as " + transformedTitle);
self.commander.log("Importing " + title + " as " + transformedTitle)
newTiddler = new $tw.Tiddler(tiddler,{title: transformedTitle});
}
} else {
self.commander.log("Importing " + title);
self.commander.log("Importing " + title)
newTiddler = tiddler;
}
self.commander.wiki.importTiddler(newTiddler);
count++;
}
});
self.commander.log("Imported " + count + " tiddlers");
self.commander.log("Imported " + count + " tiddlers")
};
exports.Command = Command;

View File

@@ -22,7 +22,8 @@ var Command = function(params,commander,callback) {
Command.prototype.execute = function() {
var self = this,
fs = require("fs");
fs = require("fs"),
path = require("path");
if(this.params.length < 2) {
return "Missing parameters";
}

View File

@@ -20,7 +20,8 @@ var Command = function(params,commander) {
};
Command.prototype.execute = function() {
var fs = require("fs");
var fs = require("fs"),
path = require("path");
// Check that we don't already have a valid wiki folder
if($tw.boot.wikiTiddlersPath || ($tw.utils.isDirectory($tw.boot.wikiPath) && !$tw.utils.isDirectoryEmpty($tw.boot.wikiPath))) {
return "Wiki folder is not empty";

View File

@@ -19,6 +19,7 @@ exports.info = {
};
var Command = function(params,commander,callback) {
var self = this;
this.params = params;
this.commander = commander;
this.callback = callback;

View File

@@ -21,7 +21,9 @@ var Command = function(params,commander,callback) {
};
Command.prototype.execute = function() {
var self = this;
var self = this,
fs = require("fs"),
path = require("path");
if(this.params.length < 1) {
return "Missing filename";
}

View File

@@ -21,7 +21,8 @@ var Command = function(params,commander,callback) {
};
Command.prototype.execute = function() {
var path = require("path");
var fs = require("fs"),
path = require("path");
if(this.params.length < 1) {
return "Missing output path";
}

View File

@@ -7,57 +7,59 @@ Render individual tiddlers and save the results to the specified files
\*/
"use strict";
"use strict";
exports.info = {
name: "render",
synchronous: true
};
var widget = require("$:/core/modules/widgets/widget.js");
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
exports.info = {
name: "render",
synchronous: true
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
if(filenameResults.length > 0) {
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
if(self.commander.verbose) {
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent;
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
} else {
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing tiddler filter";
}
});
return null;
};
var self = this,
fs = require("fs"),
path = require("path"),
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
type = this.params[2] || "text/html",
template = this.params[3],
variableList = this.params.slice(4),
tiddlers = wiki.filterTiddlers(tiddlerFilter),
variables = Object.create(null);
while(variableList.length >= 2) {
variables[variableList[0]] = variableList[1];
variableList = variableList.slice(2);
}
$tw.utils.each(tiddlers,function(title) {
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
if(filenameResults.length > 0) {
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
if(self.commander.verbose) {
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
}
var parser = wiki.parseTiddler(template || title),
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
container = $tw.fakeDocument.createElement("div");
widgetNode.render(container,null);
var text = type === "text/html" ? container.innerHTML : container.textContent;
$tw.utils.createFileDirectories(filepath);
fs.writeFileSync(filepath,text,"utf8");
} else {
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
}
});
return null;
};
exports.Command = Command;
exports.Command = Command;

View File

@@ -9,6 +9,8 @@ Command to render several tiddlers to a folder of files
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "rendertiddlers",
synchronous: true

View File

@@ -7,56 +7,57 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
\*/
"use strict";
"use strict";
exports.info = {
name: "save",
synchronous: true
};
exports.info = {
name: "save",
synchronous: true
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
var Command = function(params,commander,callback) {
this.params = params;
this.commander = commander;
this.callback = callback;
};
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
var self = this,
path = require("path"),
result = null,
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
if(!result) {
var tiddler = self.commander.wiki.getTiddler(title);
if(tiddler) {
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: path.resolve(self.commander.outputPath),
pathFilters: [filenameFilter],
wiki: wiki,
fileInfo: {
overwrite: true
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
}
try {
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
} catch (err) {
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
}
} else {
result = "Tiddler '" + title + "' not found";
}
Command.prototype.execute = function() {
if(this.params.length < 1) {
return "Missing filename filter";
}
});
return result;
};
var self = this,
fs = require("fs"),
path = require("path"),
result = null,
wiki = this.commander.wiki,
tiddlerFilter = this.params[0],
filenameFilter = this.params[1] || "[is[tiddler]]",
tiddlers = wiki.filterTiddlers(tiddlerFilter);
$tw.utils.each(tiddlers,function(title) {
if(!result) {
var tiddler = self.commander.wiki.getTiddler(title);
if(tiddler) {
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
directory: path.resolve(self.commander.outputPath),
pathFilters: [filenameFilter],
wiki: wiki,
fileInfo: {
overwrite: true
}
});
if(self.commander.verbose) {
console.log("Saving \"" + title + "\" to \"" + fileInfo.filepath + "\"");
}
try {
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
} catch (err) {
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
}
} else {
result = "Tiddler '" + title + "' not found";
}
}
});
return result;
};
exports.Command = Command;
exports.Command = Command;

View File

@@ -9,6 +9,8 @@ Command to save several tiddlers to a folder of files
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "savetiddlers",
synchronous: true

View File

@@ -43,7 +43,7 @@ Command.prototype.execute = function() {
namedParames,
tiddlerFilter,
options = {};
if(regFilter.test(this.params[1])) {
if (regFilter.test(this.params[1])) {
namedParames = this.commander.extractNamedParameters(this.params.slice(1));
tiddlerFilter = namedParames.filter || "[all[tiddlers]]";
} else {
@@ -177,13 +177,13 @@ WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
$tw.utils.each(pluginTiddlers,function(tiddler,title) {
if(!tiddler.title) {
tiddler.title = title;
}
}
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
});
};
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
var fileInfo, pathFilters, extFilters;
var title = tiddler.fields.title, fileInfo, pathFilters, extFilters;
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
}

View File

@@ -17,6 +17,7 @@ exports.info = {
};
var Command = function(params,commander,callback) {
var self = this;
this.params = params;
this.commander = commander;
this.callback = callback;

View File

@@ -9,6 +9,8 @@ Command to modify selected tiddlers to set a field to the text of a template tid
"use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = {
name: "setfield",
synchronous: true
@@ -24,7 +26,8 @@ Command.prototype.execute = function() {
if(this.params.length < 4) {
return "Missing parameters";
}
var wiki = this.commander.wiki,
var self = this,
wiki = this.commander.wiki,
filter = this.params[0],
fieldname = this.params[1] || "text",
templatetitle = this.params[2],

View File

@@ -26,7 +26,7 @@ exports.getSubdirectories = function(dirPath) {
}
});
return subdirs;
};
}
/*
Recursively (and synchronously) copy a directory and all its content
@@ -46,7 +46,8 @@ exports.copyDirectory = function(srcPath,dstPath) {
}
// Function to copy a folder full of files
var copy = function(srcPath,dstPath) {
var srcStats = fs.lstatSync(srcPath);
var srcStats = fs.lstatSync(srcPath),
dstExists = fs.existsSync(dstPath);
if(srcStats.isFile()) {
$tw.utils.copyFile(srcPath,dstPath);
} else if(srcStats.isDirectory()) {
@@ -82,7 +83,7 @@ exports.copyFile = function(srcPath,dstPath) {
dstFile = fs.openSync(dstPath,"w"),
bytesRead = 1,
pos = 0;
while(bytesRead > 0) {
while (bytesRead > 0) {
bytesRead = fs.readSync(srcFile,fileBuffer,0,FILE_BUFFER_LENGTH,pos);
fs.writeSync(dstFile,fileBuffer,0,bytesRead);
pos += bytesRead;
@@ -147,7 +148,7 @@ exports.deleteDirectory = function(dirPath) {
fs.unlinkSync(currPath);
}
}
fs.rmdirSync(dirPath);
fs.rmdirSync(dirPath);
}
return null;
};
@@ -254,7 +255,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
// Overriding to the .tid extension needs special handling
fileInfo.type = "application/x-tiddler";
fileInfo.hasMetaFile = false;
} else if(metaExt === ".json") {
} else if (metaExt === ".json") {
// Overriding to the .json extension needs special handling
fileInfo.type = "application/json";
fileInfo.hasMetaFile = false;
@@ -344,18 +345,18 @@ exports.generateTiddlerFilepath = function(title,options) {
// Replace any Windows control codes
filepath = filepath.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
// Replace any leading spaces with the same number of underscores
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_");});
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_")});
//If the path does not start with "." or ".." && a path seperator, then
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
// Don't let the filename start with any dots because such files are invisible on *nix
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_");});
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_")});
}
// Replace any Unicode control codes
filepath = filepath.replace(/[\x00-\x1f\x80-\x9f]/g,"_");
// Replace any characters that can't be used in cross-platform filenames
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
// Replace any dots or spaces at the end of the extension with the same number of underscores
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_");});
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_")});
// Truncate the extension if it is too long
if(extension.length > 32) {
extension = extension.substr(0,32);
@@ -381,9 +382,9 @@ exports.generateTiddlerFilepath = function(title,options) {
}
// Add a uniquifier if the file already exists (default)
var fullPath = path.resolve(directory, filepath + extension);
if(!overwrite) {
if (!overwrite) {
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
count = 0;
count = 0;
do {
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
if(oldPath && oldPath == fullPath) break;
@@ -400,7 +401,7 @@ exports.generateTiddlerFilepath = function(title,options) {
writePath.indexOf(path.resolve(directory)) == 0 ||
writePath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
}
}
if(encode) {
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath));
}
@@ -520,12 +521,12 @@ Cleanup old files on disk, by comparing the options values:
*/
exports.cleanupTiddlerFiles = function(options,callback) {
var adaptorInfo = options.adaptorInfo || {},
bootInfo = options.bootInfo || {},
title = options.title || "undefined";
bootInfo = options.bootInfo || {},
title = options.title || "undefined";
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
$tw.utils.deleteTiddlerFile(adaptorInfo,function(err) {
if(err) {
if((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
// Error deleting the previous file on disk, should fail gracefully
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: \""+title+"\"",err);
return callback(null,bootInfo);

View File

@@ -10,7 +10,9 @@ Authenticator for WWW basic authentication
"use strict";
if($tw.node) {
var fs = require("fs"),
var util = require("util"),
fs = require("fs"),
url = require("url"),
path = require("path");
}

View File

@@ -19,7 +19,7 @@ exports.info = {
exports.handler = function(request,response,state) {
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
responseHeaders = {
"Content-Type": state.server.get("root-serve-type")
};
"Content-Type": state.server.get("root-serve-type")
};
state.sendResponse(200,responseHeaders,text);
};

View File

@@ -18,7 +18,7 @@ exports.info = {
exports.handler = function(request,response,state) {
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
fields = $tw.utils.parseJSONSafe(state.data);
fields = $tw.utils.parseJSONSafe(state.data);
// Pull up any subfields in the `fields` object
if(fields.fields) {
$tw.utils.each(fields.fields,function(field,name) {

View File

@@ -9,15 +9,14 @@ Serve tiddlers over http
"use strict";
let fs, url, path, querystring, crypto, zlib;
if($tw.node) {
fs = require("fs"),
url = require("url"),
path = require("path"),
querystring = require("querystring"),
crypto = require("crypto"),
zlib = require("zlib");
var util = require("util"),
fs = require("fs"),
url = require("url"),
path = require("path"),
querystring = require("querystring"),
crypto = require("crypto"),
zlib = require("zlib");
}
/*
@@ -42,7 +41,7 @@ function Server(options) {
}
}
// Setup the default required plugins
this.requiredPlugins = this.get("required-plugins").split(",");
this.requiredPlugins = this.get("required-plugins").split(',');
// Initialise CORS
this.corsEnable = this.get("cors-enable") === "yes";
// Initialise CSRF
@@ -63,9 +62,9 @@ function Server(options) {
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);
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
}
// Load and initialise authenticators
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
@@ -92,7 +91,7 @@ function Server(options) {
this.listenOptions = {
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
passphrase: tlsPassphrase || ""
passphrase: tlsPassphrase || ''
};
this.protocol = "https";
}
@@ -117,7 +116,7 @@ encoding: the encoding of the data to send (passed to the end method of the resp
*/
function sendResponse(request,response,statusCode,headers,data,encoding) {
if(this.enableBrowserCache && (statusCode == 200)) {
var hash = crypto.createHash("md5");
var hash = crypto.createHash('md5');
// Put everything into the hash that could change and invalidate the data that
// the browser already stored. The headers the data and the encoding.
hash.update(data);
@@ -212,6 +211,7 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
Server.prototype.findMatchingRoute = function(request,state) {
for(var t=0; t<this.routes.length; t++) {
var potentialRoute = this.routes[t],
pathRegExp = potentialRoute.path,
pathname = state.urlInfo.pathname,
match;
if(state.pathPrefix) {
@@ -250,7 +250,7 @@ Check whether a given user is authorized for the specified authorizationType ("r
Server.prototype.isAuthorized = function(authorizationType,username) {
var principals = this.authorizationPrincipals[authorizationType] || [];
return principals.indexOf("(anon)") !== -1 || (username && (principals.indexOf("(authenticated)") !== -1 || principals.indexOf(username) !== -1));
};
}
Server.prototype.requestHandler = function(request,response,options) {
options = options || {};
@@ -337,7 +337,7 @@ Server.prototype.requestHandler = function(request,response,options) {
request.on("end",function() {
state.data = Buffer.concat(data);
route.handler(request,response,state);
});
})
} else {
response.writeHead(400,"Invalid bodyFormat " + route.bodyFormat + " in route " + route.method + " " + route.path.source);
response.end();
@@ -362,8 +362,8 @@ Server.prototype.listen = function(port,host,prefix) {
}
// Warn if required plugins are missing
var missing = [];
for(var index=0; index<this.requiredPlugins.length; index++) {
if(!this.wiki.getTiddler(this.requiredPlugins[index])) {
for (var index=0; index<this.requiredPlugins.length; index++) {
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
missing.push(this.requiredPlugins[index]);
}
}

View File

@@ -9,22 +9,22 @@ Base64 UTF-8 utlity functions.
"use strict";
const { TextEncoder, TextDecoder } = require("node:util");
const{ TextEncoder, TextDecoder } = require("node:util");
exports.btoa = (binstr) => Buffer.from(binstr, "binary").toString("base64");
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
exports.atob = (b64) => Buffer.from(b64, "base64").toString("binary");
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
function base64ToBytes(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, (m) => m.codePointAt(0));
return Uint8Array.from(binString, m => m.codePointAt(0));
};
function bytesToBase64(bytes) {
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = (str) => bytesToBase64(new TextEncoder().encode(str));
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
exports.base64DecodeUtf8 = (str) => new TextDecoder().decode(base64ToBytes(str));
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));

View File

@@ -16,7 +16,8 @@ ignoreEnvironmentVariables: defaults to false
*/
exports.getAllPlugins = function(options) {
options = options || {};
var path = require("path"),
var fs = require("fs"),
path = require("path"),
tiddlers = {};
// Collect up the library plugins
var collectPlugins = function(folder) {

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/background-actions.js
type: application/javascript
module-type: global
Class to dispatch actions when filters change
\*/
"use strict";
@@ -15,16 +12,16 @@ class BackgroundActionDispatcher {
this.wiki = wiki;
this.nextTrackedFilterId = 1;
this.trackedFilters = new Map(); // Use Map for better key management
// Track the filter for the background actions
this.filterTracker.track({
filterString: "[all[tiddlers+shadows]tag[$:/tags/BackgroundAction]!is[draft]]",
fnEnter: (title) => this.trackFilter(title),
fnEnter: title => this.trackFilter(title),
fnLeave: (title, enterValue) => this.untrackFilter(enterValue),
fnChange: (title, enterValue) => {
this.untrackFilter(enterValue);
return this.trackFilter(title);
},
fnProcess: (changes) => this.process(changes)
fnProcess: changes => this.process(changes)
});
}
@@ -56,13 +53,6 @@ class BackgroundActionDispatcher {
}
}
/*
Represents an individual tracked filter. Options include:
wiki: wiki to use
title: title of the tiddler being tracked
trackFilter: filter string to track changes
actions: actions to be executed when the filter changes
*/
class BackgroundActionTracker {
constructor({wiki, title, trackFilter, actions}) {
this.wiki = wiki;
@@ -75,7 +65,7 @@ class BackgroundActionTracker {
filterString: this.trackFilter,
fnEnter: () => { this.hasChanged = true; },
fnLeave: () => { this.hasChanged = true; },
fnProcess: (changes) => {
fnProcess: changes => {
if(this.hasChanged) {
this.hasChanged = false;
console.log("Processing background action", this.title);

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/config.js
type: application/javascript
module-type: config
Core configuration constants
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/deserializers.js
type: application/javascript
module-type: tiddlerdeserializer
Functions to deserialise tiddlers from a block of text
\*/
"use strict";
@@ -37,12 +34,6 @@ exports["application/json"] = function(text,fields) {
return results;
};
/*
Parse an HTML file into tiddlers. There are three possibilities:
# A TiddlyWiki classic HTML file containing `text/x-tiddlywiki` tiddlers
# A TiddlyWiki5 HTML file containing `text/vnd.tiddlywiki` tiddlers
# An ordinary HTML file
*/
exports["text/html"] = function(text,fields) {
var results = [];
// Check if we've got an old-style store area
@@ -60,11 +51,11 @@ exports["text/html"] = function(text,fields) {
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
}
// Return if we had either an old-style or a new-style store area
if(storeAreaMatch || haveHadNewStoreArea) {
return results;
}
// Otherwise, check whether we've got an encrypted file
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
if(encryptedStoreArea) {
// If so, attempt to decrypt it using the current password
@@ -124,30 +115,18 @@ function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
return results;
}
/*
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
<pre>The text of the tiddler (without the expected HTML encoding).
</pre>
</div>
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
*/
var deserializeTiddlerDiv = function(text /* [,fields] */) {
var deserializeTiddlerDiv = function(text) {
// Slot together the default results
var result = {};
if(arguments.length > 1) {
for(var f=1; f<arguments.length; f++) {
var fields = arguments[f];
for(var t in fields) {
result[t] = fields[t];
result[t] = fields[t];
}
}
}
// Parse the DIV body
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
endRegExp,
match = startRegExp.exec(text);

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/engines/framed.js
type: application/javascript
module-type: library
Text editor engine based on a simple input or textarea within an iframe. This is done so that the selection is preserved even when clicking away from the textarea
\*/
"use strict";
@@ -56,7 +53,7 @@ function FramedEngine(options) {
} else {
this.domNode.value = this.value;
}
// Set the attributes
if(this.widget.editType && this.widget.editTag !== "textarea") {
this.domNode.setAttribute("type",this.widget.editType);
}
@@ -78,7 +75,7 @@ function FramedEngine(options) {
if(this.widget.isDisabled === "yes") {
this.domNode.setAttribute("disabled",true);
}
// Copy the styles from the dummy textarea
this.copyStyles();
// Add event listeners
$tw.utils.addEventListeners(this.domNode,[
@@ -99,13 +96,10 @@ function FramedEngine(options) {
{name: "click",handlerObject: this.widget,handlerMethod: "handleClickEvent"}
]);
}
// Insert the element into the DOM
this.iframeDoc.body.appendChild(this.domNode);
}
/*
Copy styles from the dummy text area to the textarea in the iframe
*/
FramedEngine.prototype.copyStyles = function() {
// Copy all styles
$tw.utils.copyStyles(this.dummyTextArea,this.domNode);
@@ -127,14 +121,11 @@ FramedEngine.prototype.setText = function(text,type) {
if(this.domNode.ownerDocument.activeElement !== this.domNode) {
this.updateDomNodeText(text);
}
// Fix the height if needed
this.fixHeight();
}
};
/*
Update the DomNode with the new text
*/
FramedEngine.prototype.updateDomNodeText = function(text) {
try {
this.domNode.value = text;
@@ -143,16 +134,10 @@ FramedEngine.prototype.updateDomNodeText = function(text) {
}
};
/*
Get the text of the engine
*/
FramedEngine.prototype.getText = function() {
return this.domNode.value;
};
/*
Fix the height of textarea to fit content
*/
FramedEngine.prototype.fixHeight = function() {
// Make sure styles are updated
this.copyStyles();
@@ -172,9 +157,6 @@ FramedEngine.prototype.fixHeight = function() {
}
};
/*
Focus the engine node
*/
FramedEngine.prototype.focus = function() {
if(this.domNode.focus) {
this.domNode.focus();
@@ -184,37 +166,25 @@ FramedEngine.prototype.focus = function() {
}
};
/*
Handle a focus event
*/
FramedEngine.prototype.handleFocusEvent = function(event) {
if(this.widget.editCancelPopups) {
$tw.popup.cancel(0);
}
};
/*
Handle a keydown event
*/
FramedEngine.prototype.handleKeydownEvent = function(event) {
if($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
return true;
}
return this.widget.handleKeydownEvent(event);
};
/*
Handle a click
*/
FramedEngine.prototype.handleClickEvent = function(event) {
this.fixHeight();
return true;
};
/*
Handle a dom "input" event which occurs when the text has changed
*/
FramedEngine.prototype.handleInputEvent = function(event) {
this.widget.saveChanges(this.getText());
this.fixHeight();
@@ -224,9 +194,6 @@ FramedEngine.prototype.handleInputEvent = function(event) {
return true;
};
/*
Create a blank structure representing a text operation
*/
FramedEngine.prototype.createTextOperation = function() {
var operation = {
text: this.domNode.value,
@@ -242,9 +209,6 @@ FramedEngine.prototype.createTextOperation = function() {
return operation;
};
/*
Execute a text operation
*/
FramedEngine.prototype.executeTextOperation = function(operation) {
// Perform the required changes to the text area and the underlying tiddler
var newText = operation.text;

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/engines/simple.js
type: application/javascript
module-type: library
Text editor engine based on a simple input or textarea tag
\*/
"use strict";
@@ -30,7 +27,7 @@ function SimpleEngine(options) {
} else {
this.domNode.value = this.value;
}
// Set the attributes
if(this.widget.editType && this.widget.editTag !== "textarea") {
this.domNode.setAttribute("type",this.widget.editType);
}
@@ -55,7 +52,7 @@ function SimpleEngine(options) {
if(this.widget.isDisabled === "yes") {
this.domNode.setAttribute("disabled",true);
}
// Add an input event handler
$tw.utils.addEventListeners(this.domNode,[
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
{name: "input", handlerObject: this, handlerMethod: "handleInputEvent"}
@@ -65,22 +62,16 @@ function SimpleEngine(options) {
this.widget.domNodes.push(this.domNode);
}
/*
Set the text of the engine if it doesn't currently have focus
*/
SimpleEngine.prototype.setText = function(text,type) {
if(!this.domNode.isTiddlyWikiFakeDom) {
if(this.domNode.ownerDocument.activeElement !== this.domNode || text === "") {
this.updateDomNodeText(text);
}
// Fix the height if needed
this.fixHeight();
}
};
/*
Update the DomNode with the new text
*/
SimpleEngine.prototype.updateDomNodeText = function(text) {
try {
this.domNode.value = text;
@@ -89,16 +80,10 @@ SimpleEngine.prototype.updateDomNodeText = function(text) {
}
};
/*
Get the text of the engine
*/
SimpleEngine.prototype.getText = function() {
return this.domNode.value;
};
/*
Fix the height of textarea to fit content
*/
SimpleEngine.prototype.fixHeight = function() {
// If .editRows is initialised, it takes precedence
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
@@ -114,9 +99,6 @@ SimpleEngine.prototype.fixHeight = function() {
}
};
/*
Focus the engine node
*/
SimpleEngine.prototype.focus = function() {
if(this.domNode.focus) {
this.domNode.focus();
@@ -126,9 +108,6 @@ SimpleEngine.prototype.focus = function() {
}
};
/*
Handle a dom "input" event which occurs when the text has changed
*/
SimpleEngine.prototype.handleInputEvent = function(event) {
this.widget.saveChanges(this.getText());
this.fixHeight();
@@ -138,9 +117,6 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
return true;
};
/*
Handle a dom "focus" event
*/
SimpleEngine.prototype.handleFocusEvent = function(event) {
if(this.widget.editCancelPopups) {
$tw.popup.cancel(0);
@@ -156,16 +132,10 @@ SimpleEngine.prototype.handleFocusEvent = function(event) {
return true;
};
/*
Create a blank structure representing a text operation
*/
SimpleEngine.prototype.createTextOperation = function() {
return null;
};
/*
Execute a text operation
*/
SimpleEngine.prototype.executeTextOperation = function(operation) {
};

View File

@@ -2,16 +2,12 @@
title: $:/core/modules/editor/factory.js
type: application/javascript
module-type: library
Factory for constructing text editor widgets with specified engines for the toolbar and non-toolbar cases
\*/
"use strict";
var DEFAULT_MIN_TEXT_AREA_HEIGHT = "100px"; // Minimum height of textareas in pixels
// Configuration tiddlers
var HEIGHT_MODE_TITLE = "$:/config/TextEditor/EditorHeight/Mode";
var ENABLE_TOOLBAR_TITLE = "$:/config/TextEditor/EnableToolbar";
@@ -55,12 +51,12 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
var editInfo = this.getEditInfo(),
Engine = this.editShowToolbar ? toolbarEngine : nonToolbarEngine;
this.engine = new Engine({
widget: this,
value: editInfo.value,
type: editInfo.type,
parentNode: parent,
nextSibling: nextSibling
});
widget: this,
value: editInfo.value,
type: editInfo.type,
parentNode: parent,
nextSibling: nextSibling
});
// Call the postRender hook
if(this.postRender) {
this.postRender();
@@ -141,9 +137,6 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
return {value: value || "", type: type, update: update};
};
/*
Handle an edit text operation message from the toolbar
*/
EditTextWidget.prototype.handleEditTextOperationMessage = function(event) {
// Prepare information about the operation
var operation = this.engine.createTextOperation();
@@ -152,16 +145,13 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
if(handler) {
handler.call(this,event,operation);
}
// Execute the operation via the engine
var newText = this.engine.executeTextOperation(operation);
// Fix the tiddler height and save changes
this.engine.fixHeight();
this.saveChanges(newText);
};
/*
Compute the internal state of the widget
*/
EditTextWidget.prototype.execute = function() {
// Get our parameters
this.editTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
@@ -201,7 +191,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}
type = type || "text";
}
// Get the rest of our parameters
this.editTag = this.getAttribute("tag",tag) || "input";
this.editType = this.getAttribute("type",type);
// Make the child widgets
@@ -211,16 +201,13 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.editShowToolbar = (this.editShowToolbar === "yes") && !!(this.children && this.children.length > 0) && (!this.document.isTiddlyWikiFakeDom);
};
/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
EditTextWidget.prototype.refresh = function(changedTiddlers) {
var changedAttributes = this.computeAttributes();
// Completely rerender if any of our attributes have changed
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
this.refreshSelf();
return true;
} else if(changedTiddlers[this.editRefreshTitle]) {
} else if (changedTiddlers[this.editRefreshTitle]) {
this.engine.updateDomNodeText(this.getEditInfo().value);
} else if(changedTiddlers[this.editTitle]) {
var editInfo = this.getEditInfo();
@@ -234,24 +221,14 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}
};
/*
Update the editor with new text. This method is separate from updateEditorDomNode()
so that subclasses can override updateEditor() and still use updateEditorDomNode()
*/
EditTextWidget.prototype.updateEditor = function(text,type) {
this.updateEditorDomNode(text,type);
};
/*
Update the editor dom node with new text
*/
EditTextWidget.prototype.updateEditorDomNode = function(text,type) {
this.engine.setText(text,type);
};
/*
Save changes back to the tiddler store
*/
EditTextWidget.prototype.saveChanges = function(text) {
var editInfo = this.getEditInfo();
if(text !== editInfo.value) {
@@ -259,9 +236,6 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}
};
/*
Handle a dom "keydown" event, which we'll bubble up to our container for the keyboard widgets benefit
*/
EditTextWidget.prototype.handleKeydownEvent = function(event) {
// Check for a keyboard shortcut
if(this.toolbarNode) {
@@ -274,28 +248,25 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
});
if($tw.keyboardManager.checkKeyDescriptors(event,keyInfoArray)) {
var clickEvent = this.document.createEvent("Events");
clickEvent.initEvent("click",true,false);
el.dispatchEvent(clickEvent);
clickEvent.initEvent("click",true,false);
el.dispatchEvent(clickEvent);
event.preventDefault();
event.stopPropagation();
return true;
}
}
}
// Propogate the event to the container
if(this.propogateKeydownEvent(event)) {
// Ignore the keydown if it was already handled
event.preventDefault();
event.stopPropagation();
return true;
}
// Otherwise, process the keydown normally
return false;
};
/*
Propogate keydown events to our container for the keyboard widgets benefit
*/
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
var newEvent = this.cloneEvent(event,["keyCode","code","which","key","metaKey","ctrlKey","altKey","shiftKey"]);
return !this.parentDomNode.dispatchEvent(newEvent);
@@ -318,16 +289,12 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
return dispatchNode.dispatchEvent(newEvent);
};
/*
Propogate drag and drop events with File data to our container for the dropzone widgets benefit.
If there are no Files, let the browser handle it.
*/
EditTextWidget.prototype.handleDropEvent = function(event) {
if($tw.utils.dragEventContainsFiles(event)) {
event.preventDefault();
event.stopPropagation();
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
}
}
};
EditTextWidget.prototype.handlePasteEvent = function(event) {

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/bitmap/clear.js
type: application/javascript
module-type: bitmapeditoroperation
Bitmap editor operation to clear the image
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/bitmap/resize.js
type: application/javascript
module-type: bitmapeditoroperation
Bitmap editor operation to resize the image
\*/
"use strict";
@@ -17,7 +14,7 @@ exports["resize"] = function(event) {
if(newWidth > 0 && newHeight > 0 && !(newWidth === this.currCanvas.width && newHeight === this.currCanvas.height)) {
this.changeCanvasSize(newWidth,newHeight);
}
// Update the input controls
this.refreshToolbar();
// Save the image into the tiddler
this.saveChanges();

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/bitmap/rotate-left.js
type: application/javascript
module-type: bitmapeditoroperation
Bitmap editor operation to rotate the image left by 90 degrees
\*/
"use strict";

View File

@@ -2,15 +2,12 @@
title: $:/core/modules/editor/operations/text/excise.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to excise the selection to a new tiddler
\*/
"use strict";
function isMarkdown(mediaType) {
return mediaType === "text/markdown" || mediaType === "text/x-markdown";
return mediaType === 'text/markdown' || mediaType === 'text/x-markdown';
}
exports["excise"] = function(event,operation) {

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/insert-text.js
type: application/javascript
module-type: texteditoroperation
Text editor operation insert text at the caret position. If there is a selection it is replaced.
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/make-link.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to make a link
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/prefix-lines.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to add a prefix to the selected lines
\*/
"use strict";
@@ -26,16 +23,16 @@ exports["prefix-lines"] = function(event,operation) {
line = line.substring(event.paramObject.character.length);
count++;
}
// Remove any whitespace
while(line.charAt(0) === " ") {
line = line.substring(1);
}
// We're done if we removed the exact required prefix, otherwise add it
if(count !== targetCount) {
// Apply the prefix
line = prefix + " " + line;
}
// Save the modified line
lines[index] = line;
});
// Stitch the replacement text together and set the selection

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/replace-all.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to replace the entire text
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/replace-selection.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to replace the selection
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/save-selection.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to save the current selection in a specified tiddler
\*/
"use strict";

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/wrap-lines.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to wrap the selected lines with a prefix and suffix
\*/
"use strict";
@@ -15,14 +12,14 @@ exports["wrap-lines"] = function(event,operation) {
if($tw.utils.endsWith(operation.text.substring(0,operation.selStart), prefix + "\n") &&
$tw.utils.startsWith(operation.text.substring(operation.selEnd), "\n" + suffix)) {
// Selected text is already surrounded by prefix and suffix: Remove them
// Cut selected text plus prefix and suffix
operation.cutStart = operation.selStart - (prefix.length + 1);
operation.cutEnd = operation.selEnd + suffix.length + 1;
// Also cut the following newline (if there is any)
if(operation.text[operation.cutEnd] === "\n") {
if (operation.text[operation.cutEnd] === "\n") {
operation.cutEnd++;
}
// Replace with selection
operation.replacement = operation.text.substring(operation.selStart,operation.selEnd);
// Select text that was in between prefix and suffix
operation.newSelStart = operation.cutStart;

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/editor/operations/text/wrap-selection.js
type: application/javascript
module-type: texteditoroperation
Text editor operation to wrap the selection with the specified prefix and suffix
\*/
"use strict";
@@ -17,11 +14,11 @@ exports["wrap-selection"] = function(event,operation) {
selLength = o.selEnd - o.selStart;
// This function detects, if trailing spaces are part of the selection __and__ if the user wants to handle them
// Returns "yes", "start", "end", "no" (default)
// yes .. there are trailing spaces at both ends
// start .. there are trailing spaces at the start
// end .. there are trailing spaces at the end
// no .. no trailing spaces are taken into account
var trailingSpaceAt = function(sel) {
var _start,
_end,
@@ -44,7 +41,7 @@ exports["wrap-selection"] = function(event,operation) {
break;
}
return result;
};
}
function togglePrefixSuffix() {
if(o.text.substring(o.selStart - prefix.length, o.selStart + suffix.length) === prefix + suffix) {
@@ -64,7 +61,6 @@ exports["wrap-selection"] = function(event,operation) {
}
}
// options: lenPrefix, lenSuffix
function removePrefixSuffix(options) {
options = options || {};
var _lenPrefix = options.lenPrefix || 0;

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/filter-tracker.js
type: application/javascript
module-type: global
Class to track the results of a filter string
\*/
"use strict";
@@ -21,14 +18,6 @@ class FilterTracker {
this.processChanges(changes);
}
/*
Add a tracker to the filter tracker. Returns null if any of the parameters are invalid, or a tracker id if the tracker was added successfully. Options include:
filterString: the filter string to track
fnEnter: function to call when a title enters the filter results. Called even if the tiddler does not actually exist. Called as (title), and should return a truthy value that is stored in the tracker as the "enterValue"
fnLeave: function to call when a title leaves the filter results. Called as (title,enterValue)
fnChange: function to call when a tiddler changes in the filter results. Only called for filter results that identify a tiddler or shadow tiddler. Called as (title,enterValue), and may optionally return a replacement enterValue
fnProcess: function to call each time the tracker is processed, after any enter, leave or change functions are called. Called as (changes)
*/
track(options = {}) {
const {
filterString,
@@ -69,17 +58,17 @@ class FilterTracker {
if(!tracker) return;
const results = [];
// Evaluate the filter and remove duplicate results
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), (title) => {
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), title => {
$tw.utils.pushTop(results, title);
});
// Process the newly entered results
results.forEach((title) => {
results.forEach(title => {
if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) {
tracker.resultValues[title] = tracker.fnEnter(title) || true;
}
});
// Process the results that have just left
tracker.previousResults.forEach((title) => {
tracker.previousResults.forEach(title => {
if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) {
tracker.fnLeave(title, tracker.resultValues[title]);
delete tracker.resultValues[title];
@@ -91,7 +80,7 @@ class FilterTracker {
processChanges(changes) {
for(const tracker of this.trackers.values()) {
Object.keys(changes).forEach((title) => {
Object.keys(changes).forEach(title => {
if(title && tracker.previousResults.includes(title) && tracker.fnChange) {
tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title];
}

View File

@@ -2,17 +2,10 @@
title: $:/core/modules/filterrunprefixes/all.js
type: application/javascript
module-type: filterrunprefix
Union of sets without de-duplication.
Equivalent to = filter run prefix.
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.all = function(operationSubFunction) {
return function(results,source,widget) {
results.push.apply(results, operationSubFunction(source,widget));

View File

@@ -2,17 +2,10 @@
title: $:/core/modules/filterrunprefixes/and.js
type: application/javascript
module-type: filterrunprefix
Intersection of sets.
Equivalent to + filter run prefix.
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.and = function(operationSubFunction,options) {
return function(results,source,widget) {
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved

View File

@@ -6,9 +6,6 @@ module-type: filterrunprefix
"use strict";
/*
Export our filter prefix function
*/
exports.cascade = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length !== 0) {
@@ -34,5 +31,5 @@ exports.cascade = function(operationSubFunction,options) {
results.push(result);
});
}
};
}
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filterrunprefixes/else.js
type: application/javascript
module-type: filterrunprefix
Equivalent to ~ filter run prefix.
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.else = function(operationSubFunction) {
return function(results,source,widget) {
if(results.length === 0) {

View File

@@ -2,17 +2,10 @@
title: $:/core/modules/filterrunprefixes/except.js
type: application/javascript
module-type: filterrunprefix
Difference of sets.
Equivalent to - filter run prefix.
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.except = function(operationSubFunction) {
return function(results,source,widget) {
results.remove(operationSubFunction(source,widget));

View File

@@ -2,14 +2,10 @@
title: $:/core/modules/filterrunprefixes/filter.js
type: application/javascript
module-type: filterrunprefix
\*/
"use strict";
/*
Export our filter function
*/
exports.filter = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
@@ -30,5 +26,5 @@ exports.filter = function(operationSubFunction,options) {
});
results.remove(resultsToRemove);
}
};
}
};

View File

@@ -2,14 +2,10 @@
title: $:/core/modules/filterrunprefixes/intersection.js
type: application/javascript
module-type: filterrunprefix
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.intersection = function(operationSubFunction) {
return function(results,source,widget) {
if(results.length !== 0) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filterrunprefixes/let.js
type: application/javascript
module-type: filterrunprefix
Assign a value to a variable
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.let = function(operationSubFunction,options) {
// Return the filter run prefix function
return function(results,source,widget) {
@@ -28,7 +22,7 @@ exports.let = function(operationSubFunction,options) {
if(typeof name !== "string" || name.length === 0) {
return;
}
// Assign the result of the subfunction to the variable
var variables = {};
variables[name] = resultList;
// Return the variables

View File

@@ -6,9 +6,6 @@ module-type: filterrunprefix
"use strict";
/*
Export our filter prefix function
*/
exports.map = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
@@ -28,12 +25,12 @@ exports.map = function(operationSubFunction,options) {
if(filtered.length && flatten) {
$tw.utils.each(filtered,function(value) {
results.push(value);
});
})
} else {
results.push(filtered[0]||"");
}
++index;
});
}
};
}
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filterrunprefixes/or.js
type: application/javascript
module-type: filterrunprefix
Equivalent to a filter run with no prefix.
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.or = function(operationSubFunction) {
return function(results,source,widget) {
results.pushTop(operationSubFunction(source,widget));

View File

@@ -6,9 +6,6 @@ module-type: filterrunprefix
"use strict";
/*
Export our filter prefix function
*/
exports.reduce = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
@@ -31,5 +28,5 @@ exports.reduce = function(operationSubFunction,options) {
results.clear();
results.push(accumulator);
}
};
}
};

View File

@@ -2,14 +2,10 @@
title: $:/core/modules/filterrunprefixes/sort.js
type: application/javascript
module-type: filterrunprefix
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.sort = function(operationSubFunction,options) {
return function(results,source,widget) {
if(results.length > 0) {
@@ -33,15 +29,15 @@ exports.sort = function(operationSubFunction,options) {
for(var t=0; t<inputTitles.length; t++) {
indexes[t] = t;
}
// Sort the indexes
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
indexes = indexes.sort(function(a,b) {
return compareFn(sortKeys[a],sortKeys[b]);
return compareFn(sortKeys[a],sortKeys[b]);
});
// Add to results in correct order
$tw.utils.each(indexes,function(index) {
results.push(inputTitles[index]);
});
}
};
}
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filterrunprefixes/then.js
type: application/javascript
module-type: filterrunprefix
Replace results of previous runs unless empty
\*/
"use strict";
/*
Export our filter prefix function
*/
exports.then = function(operationSubFunction) {
return function(results,source,widget) {
if(results.length !== 0) {

View File

@@ -2,39 +2,28 @@
title: $:/core/modules/filters.js
type: application/javascript
module-type: wikimethod
Adds tiddler filtering methods to the $tw.Wiki object.
\*/
"use strict";
var widgetClass = require("$:/core/modules/widgets/widget.js").widget;
/* Maximum permitted filter recursion depth */
var MAX_FILTER_DEPTH = 300;
/*
Parses an operation (i.e. a run) within a filter string
operators: Array of array of operator nodes into which results should be inserted
filterString: filter string
p: start position within the string
Returns the new start position, after the parsed operation
*/
function parseFilterOperation(operators,filterString,p) {
var nextBracketPos, operator;
// Skip the starting square bracket
if(filterString.charAt(p++) !== "[") {
throw "Missing [ in filter expression";
}
// Process each operator in turn
do {
operator = {};
// Check for an operator prefix
if(filterString.charAt(p) === "!") {
operator.prefix = filterString.charAt(p++);
}
// Get the operator name
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
if(nextBracketPos === -1) {
throw "Missing [ in filter expression";
@@ -43,7 +32,7 @@ function parseFilterOperation(operators,filterString,p) {
var bracket = filterString.charAt(nextBracketPos);
operator.operator = filterString.substring(p,nextBracketPos);
// Any suffix?
var colon = operator.operator.indexOf(":");
var colon = operator.operator.indexOf(':');
if(colon > -1) {
// The raw suffix for older filters
operator.suffix = operator.operator.substring(colon + 1);
@@ -55,19 +44,19 @@ function parseFilterOperation(operators,filterString,p) {
$tw.utils.each(subsuffix.split(","),function(entry) {
entry = $tw.utils.trim(entry);
if(entry) {
operator.suffixes[operator.suffixes.length - 1].push(entry);
operator.suffixes[operator.suffixes.length - 1].push(entry);
}
});
});
}
// Empty operator means: title
else if(operator.operator === "") {
operator.operator = "title";
}
operator.operands = [];
var parseOperand = function(bracketType) {
var operand = {};
switch(bracketType) {
switch (bracketType) {
case "{": // Curly brackets
operand.indirect = true;
nextBracketPos = filterString.indexOf("}",p);
@@ -88,8 +77,8 @@ function parseFilterOperation(operators,filterString,p) {
rexMatch = rex.exec(filterString.substring(p));
if(rexMatch) {
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
// DEPRECATION WARNING
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
// DEPRECATION WARNING
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
nextBracketPos = p + rex.lastIndex - 1;
}
else {
@@ -108,7 +97,7 @@ function parseFilterOperation(operators,filterString,p) {
}
operator.operands.push(operand);
p = nextBracketPos + 1;
};
}
p = nextBracketPos + 1;
parseOperand(bracket);
@@ -125,20 +114,16 @@ function parseFilterOperation(operators,filterString,p) {
}
}
// Push this operator
operators.push(operator);
} while(filterString.charAt(p) !== "]");
// Skip the ending square bracket
if(filterString.charAt(p++) !== "]") {
throw "Missing ] in filter expression";
}
// Return the parsing position
return p;
}
/*
Parse a filter string
*/
exports.parseFilter = function(filterString) {
filterString = filterString || "";
var results = [], // Array of arrays of operator nodes {operator:,operand:}
@@ -147,11 +132,11 @@ exports.parseFilter = function(filterString) {
var whitespaceRegExp = /(\s+)/mg,
// Groups:
// 1 - entire filter run prefix
// 2 - filter run prefix itself
// 3 - filter run prefix suffixes
// 4 - opening square bracket following filter run prefix
// 5 - double quoted string following filter run prefix
// 6 - single quoted string following filter run prefix
// 7 - anything except for whitespace and square brackets
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
while(p < filterString.length) {
@@ -161,7 +146,7 @@ exports.parseFilter = function(filterString) {
if(match && match.index === p) {
p = p + match[0].length;
}
// Match the start of the operation
if(p < filterString.length) {
operandRegExp.lastIndex = p;
var operation = {
@@ -178,7 +163,7 @@ exports.parseFilter = function(filterString) {
if(match[2]) {
operation.namedPrefix = match[2];
}
// Suffixes for filter run prefix
if(match[3]) {
operation.suffixes = [];
$tw.utils.each(match[3].split(":"),function(subsuffix) {
@@ -192,7 +177,7 @@ exports.parseFilter = function(filterString) {
});
}
}
// Opening square bracket
if(match[4]) {
p = parseFilterOperation(operation.operators,filterString,p);
} else {
@@ -202,7 +187,7 @@ exports.parseFilter = function(filterString) {
// No filter run prefix
p = parseFilterOperation(operation.operators,filterString,p);
}
// Quoted strings and unquoted title
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
operation.operators.push(
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
@@ -228,18 +213,13 @@ exports.getFilterRunPrefixes = function() {
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
}
return this.filterRunPrefixes;
};
}
exports.filterTiddlers = function(filterString,widget,source) {
var fn = this.compileFilter(filterString);
return fn.call(this,source,widget);
};
/*
Compile a filter into a function with the signature fn(source,widget) where:
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
widget: an optional widget node for retrieving the current tiddler etc.
*/
exports.compileFilter = function(filterString) {
if(!this.filterCache) {
this.filterCache = Object.create(null);
@@ -257,7 +237,7 @@ exports.compileFilter = function(filterString) {
return [$tw.language.getString("Error/Filter") + ": " + e];
};
}
// Get the hashmap of filter operator functions
var filterOperators = this.getFilterOperators();
// Assemble array of functions, one for each operation
var operationFunctions = [];
@@ -302,7 +282,7 @@ exports.compileFilter = function(filterString) {
operand.value = "";
operand.multiValue = [];
}
operand.isMultiValueOperand = true;
operand.isMultiValueOperand = true;
} else {
operand.value = operand.text;
operand.multiValue = [operand.value];
@@ -314,19 +294,19 @@ exports.compileFilter = function(filterString) {
// Invoke the appropriate filteroperator module
results = operatorFunction(accumulator,{
operator: operator.operator,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
multiValueOperands: multiValueOperands,
isMultiValueOperand: isMultiValueOperand,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
operator: operator.operator,
operand: operands.length > 0 ? operands[0] : undefined,
operands: operands,
multiValueOperands: multiValueOperands,
isMultiValueOperand: isMultiValueOperand,
prefix: operator.prefix,
suffix: operator.suffix,
suffixes: operator.suffixes,
regexp: operator.regexp
},{
wiki: self,
widget: widget
});
if($tw.utils.isArray(results)) {
accumulator = self.makeTiddlerIterator(results);
} else {
@@ -360,7 +340,7 @@ exports.compileFilter = function(filterString) {
return filterRunPrefixes["else"](operationSubFunction, options);
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
return filterRunPrefixes["let"](operationSubFunction, options);
default:
default:
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
} else {
@@ -402,7 +382,7 @@ exports.compileFilter = function(filterString) {
});
if(this.filterCacheCount >= 2000) {
// To prevent memory leak, we maintain an upper limit for cache size.
// Reset if exceeded. This should give us 95% of the benefit
// that no cache limit would give us.
this.filterCache = Object.create(null);
this.filterCacheCount = 0;

View File

@@ -2,18 +2,10 @@
title: $:/core/modules/filters/addprefix.js
type: application/javascript
module-type: filteroperator
Filter operator for adding a prefix to each title in the list. This is
especially useful in contexts where only a filter expression is allowed
and macro substitution isn't available.
\*/
"use strict";
/*
Export our filter function
*/
exports.addprefix = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,18 +2,10 @@
title: $:/core/modules/filters/addsuffix.js
type: application/javascript
module-type: filteroperator
Filter operator for adding a suffix to each title in the list. This is
especially useful in contexts where only a filter expression is allowed
and macro substitution isn't available.
\*/
"use strict";
/*
Export our filter function
*/
exports.addsuffix = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/after.js
type: application/javascript
module-type: filteroperator
Filter operator returning the tiddler from the current list that is after the tiddler named in the operand.
\*/
"use strict";
/*
Export our filter function
*/
exports.after = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,11 +2,6 @@
title: $:/core/modules/filters/all.js
type: application/javascript
module-type: filteroperator
Filter operator for selecting tiddlers
[all[shadows+tiddlers]]
\*/
"use strict";
@@ -21,9 +16,6 @@ function getAllFilterOperators() {
return allFilterOperators;
}
/*
Export our filter function
*/
exports.all = function(source,operator,options) {
// Check for common optimisations
var subops = operator.operand.split("+");
@@ -38,7 +30,7 @@ exports.all = function(source,operator,options) {
} else if(subops.length === 2 && subops[0] === "shadows" && subops[1] === "tiddlers") {
return options.wiki.eachShadowPlusTiddlers;
}
// Do it the hard way
// Get our suboperators
var allFilterOperators = getAllFilterOperators();
// Cycle through the suboperators accumulating their results

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/current.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[current]]
\*/
"use strict";
/*
Export our filter function
*/
exports.current = function(source,prefix,options) {
var currTiddlerTitle = options.widget && options.widget.getVariable("currentTiddler");
if(currTiddlerTitle) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/missing.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[missing]]
\*/
"use strict";
/*
Export our filter function
*/
exports.missing = function(source,prefix,options) {
return options.wiki.getMissingTitles();
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/orphans.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[orphans]]
\*/
"use strict";
/*
Export our filter function
*/
exports.orphans = function(source,prefix,options) {
return options.wiki.getOrphanTitles();
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/shadows.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[shadows]]
\*/
"use strict";
/*
Export our filter function
*/
exports.shadows = function(source,prefix,options) {
return options.wiki.allShadowTitles();
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/tags.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[tags]]
\*/
"use strict";
/*
Export our filter function
*/
exports.tags = function(source,prefix,options) {
return Object.keys(options.wiki.getTagMap());
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/all/tiddlers.js
type: application/javascript
module-type: allfilteroperator
Filter function for [all[tiddlers]]
\*/
"use strict";
/*
Export our filter function
*/
exports.tiddlers = function(source,prefix,options) {
return options.wiki.allTitles();
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/backlinks.js
type: application/javascript
module-type: filteroperator
Filter operator for returning all the backlinks from a tiddler
\*/
"use strict";
/*
Export our filter function
*/
exports.backlinks = function(source,operator,options) {
var results = new $tw.utils.LinkedList();
source(function(tiddler,title) {

View File

@@ -2,15 +2,9 @@
title: $:/core/modules/filters/backtranscludes.js
type: application/javascript
module-type: filteroperator
Filter operator for returning all the backtranscludes from a tiddler
\*/
"use strict";
/*
Export our filter function
*/
exports.backtranscludes = function(source,operator,options) {
var results = new $tw.utils.LinkedList();
source(function(tiddler,title) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/before.js
type: application/javascript
module-type: filteroperator
Filter operator returning the tiddler from the current list that is before the tiddler named in the operand.
\*/
"use strict";
/*
Export our filter function
*/
exports.before = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/commands.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the names of the commands available in this wiki
\*/
"use strict";
/*
Export our filter function
*/
exports.commands = function(source,operator,options) {
var results = [];
$tw.utils.each($tw.commands,function(commandInfo,name) {

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/filters/compare.js
type: application/javascript
module-type: filteroperator
General purpose comparison operator
\*/
"use strict";
@@ -32,4 +29,4 @@ var modes = {
"gt": function(value) {return value > 0;},
"lteq": function(value) {return value <= 0;},
"lt": function(value) {return value < 0;}
};
}

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/contains.js
type: application/javascript
module-type: filteroperator
Filter operator for finding values in array fields
\*/
"use strict";
/*
Export our filter function
*/
exports.contains = function(source,operator,options) {
var results = [],
fieldname = operator.suffix || "list";

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/count.js
type: application/javascript
module-type: filteroperator
Filter operator returning the number of entries in the current list.
\*/
"use strict";
/*
Export our filter function
*/
exports.count = function(source,operator,options) {
var count = 0;
source(function(tiddler,title) {

View File

@@ -2,9 +2,6 @@
title: $:/core/modules/filters/crypto.js
type: application/javascript
module-type: filteroperator
Filter operators for cryptography, using the Stanford JavaScript library
\*/
"use strict";

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/days.js
type: application/javascript
module-type: filteroperator
Filter operator that selects tiddlers with a specified date field within a specified date interval.
\*/
"use strict";
/*
Export our filter function
*/
exports.days = function(source,operator,options) {
var results = [],
fieldName = operator.suffix || "modified",

View File

@@ -31,4 +31,4 @@ exports["deserialize"] = function(source,operator,options) {
return [$tw.language.getString("Error/DeserializeOperator/MissingOperand")];
}
return results;
};
}

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/deserializers.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the names of the deserializers in this wiki
\*/
"use strict";
/*
Export our filter function
*/
exports.deserializers = function(source,operator,options) {
var results = [];
$tw.utils.each($tw.Wiki.tiddlerDeserializerModules,function(deserializer,type) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/duplicateslugs.js
type: application/javascript
module-type: filteroperator
Filter function for [duplicateslugs[]]
\*/
"use strict";
/*
Export our filter function
*/
exports.duplicateslugs = function(source,operator,options) {
var slugs = Object.create(null), // Hashmap by slug of title, replaced with "true" if the duplicate title has already been output
results = [];

View File

@@ -2,21 +2,14 @@
title: $:/core/modules/filters/each.js
type: application/javascript
module-type: filteroperator
Filter operator that selects one tiddler for each unique value of the specified field.
With suffix "list", selects all tiddlers that are values in a specified list field.
\*/
"use strict";
/*
Export our filter function
*/
exports.each = function(source,operator,options) {
var results =[] ,
value,values = {},
field = operator.operand || "title";
value,values = {},
field = operator.operand || "title";
if(operator.suffix === "value" && field === "title") {
source(function(tiddler,title) {
if(!$tw.utils.hop(values,title)) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/eachday.js
type: application/javascript
module-type: filteroperator
Filter operator that selects one tiddler for each unique day covered by the specified date field
\*/
"use strict";
/*
Export our filter function
*/
exports.eachday = function(source,operator,options) {
var results = [],
values = [],

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/editiondescription.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the descriptions of the specified edition names
\*/
"use strict";
/*
Export our filter function
*/
exports.editiondescription = function(source,operator,options) {
var results = [];
if($tw.node) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/editions.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the names of the available editions in this wiki
\*/
"use strict";
/*
Export our filter function
*/
exports.editions = function(source,operator,options) {
var results = [];
if($tw.node) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/else.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing an empty input list with a constant, passing a non-empty input list straight through
\*/
"use strict";
/*
Export our filter function
*/
exports.else = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,17 +2,10 @@
title: $:/core/modules/filters/decodeuricomponent.js
type: application/javascript
module-type: filteroperator
Filter operator for applying decodeURIComponent() to each item.
\*/
"use strict";
/*
Export our filter functions
*/
exports.decodebase64 = function(source,operator,options) {
var results = [];
var binary = operator.suffixes && operator.suffixes[0].indexOf("binary") !== -1;

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/enlist.js
type: application/javascript
module-type: filteroperator
Filter operator returning its operand parsed as a list
\*/
"use strict";
/*
Export our filter function
*/
exports.enlist = function(source,operator,options) {
var allowDuplicates = false;
switch(operator.suffix) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/field.js
type: application/javascript
module-type: filteroperator
Filter operator for comparing fields for equality
\*/
"use strict";
/*
Export our filter function
*/
exports.field = function(source,operator,options) {
var results = [],indexedResults,
fieldname = operator.suffix || operator.operator || "title";
@@ -53,7 +47,7 @@ exports.field = function(source,operator,options) {
if(source.byField && operator.operand) {
indexedResults = source.byField(fieldname,operator.operand);
if(indexedResults) {
return indexedResults;
return indexedResults
}
}
source(function(tiddler,title) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/fields.js
type: application/javascript
module-type: filteroperator
Filter operator for returning the names of the fields on the selected tiddlers
\*/
"use strict";
/*
Export our filter function
*/
exports.fields = function(source,operator,options) {
var results = [],
fieldName,
@@ -24,17 +18,17 @@ exports.fields = function(source,operator,options) {
for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : "";
}
} else if(suffixes.indexOf("exclude") !== -1) {
} else if (suffixes.indexOf("exclude") !== -1) {
for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName);
}
} // else if
}
else {
for(fieldName in tiddler.fields) {
$tw.utils.pushTop(results,fieldName);
}
} // else
} // if (tiddler)
}
}
});
return results;
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/filter.js
type: application/javascript
module-type: filteroperator
Filter operator returning those input titles that pass a subfilter
\*/
"use strict";
/*
Export our filter function
*/
exports.filter = function(source,operator,options) {
var filterFn = options.wiki.compileFilter(operator.operand),
results = [],

View File

@@ -17,9 +17,6 @@ function getFormatFilterOperators() {
return formatFilterOperators;
}
/*
Export our filter function
*/
exports.format = function(source,operator,options) {
// Dispatch to the correct formatfilteroperator
var formatFilterOperators = getFormatFilterOperators();

View File

@@ -6,9 +6,6 @@ module-type: formatfilteroperator
"use strict";
/*
Export our filter function
*/
exports.date = function(source,operand,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -6,9 +6,6 @@ module-type: formatfilteroperator
"use strict";
/*
Export our filter function
*/
exports.json = function(source,operand,options) {
var results = [],
spaces = null;

View File

@@ -6,9 +6,6 @@ module-type: formatfilteroperator
"use strict";
/*
Export our filter function
*/
exports.relativedate = function(source,operand,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -6,13 +6,10 @@ module-type: formatfilteroperator
"use strict";
/*
Export our filter function
*/
exports.timestamp = function(source,operand,options) {
var results = [];
source(function(tiddler,title) {
if(title.match(/^-?\d+$/)) {
if (title.match(/^-?\d+$/)) {
var value = new Date(Number(title));
results.push($tw.utils.formatDateString(value,operand || "[UTC]YYYY0MM0DD0hh0mm0ss0XXX"));
}

View File

@@ -6,9 +6,6 @@ module-type: formatfilteroperator
"use strict";
/*
Export our filter function
*/
exports.titlelist = function(source,operand,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/function.js
type: application/javascript
module-type: filteroperator
Filter operator returning those input titles that are returned from a function
\*/
"use strict";
/*
Export our filter function
*/
exports.function = function(source,operator,options) {
var functionName = operator.operands[0],
params = [],
@@ -24,13 +18,13 @@ exports.function = function(source,operator,options) {
if(variableInfo && variableInfo.srcVariable && variableInfo.srcVariable.isFunctionDefinition) {
results = variableInfo.resultList ? variableInfo.resultList : [variableInfo.text];
}
// Return the input list if the function wasn't found
if(!results) {
results = [];
source(function(tiddler,title) {
results.push(title);
});
});
}
// console.log(`function ${functionName} with params ${JSON.stringify(params)} results: ${JSON.stringify(results)}`);
return results;
};

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/get.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing tiddler titles by the value of the field specified in the operand.
\*/
"use strict";
/*
Export our filter function
*/
exports.get = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

View File

@@ -2,18 +2,12 @@
title: $:/core/modules/filters/getindex.js
type: application/javascript
module-type: filteroperator
returns the value at a given index of datatiddlers
\*/
"use strict";
/*
Export our filter function
*/
exports.getindex = function(source,operator,options) {
var data,results = [];
var data,title,results = [];
if(operator.operand){
source(function(tiddler,title) {
title = tiddler ? tiddler.fields.title : title;

View File

@@ -2,16 +2,10 @@
title: $:/core/modules/filters/getvariable.js
type: application/javascript
module-type: filteroperator
Filter operator for replacing input values by the value of the variable with the same name, or blank if the variable is missing
\*/
"use strict";
/*
Export our filter function
*/
exports.getvariable = function(source,operator,options) {
var results = [];
source(function(tiddler,title) {

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