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

Compare commits

..

10 Commits

Author SHA1 Message Date
lin onetwo
431b7fa3bf Update ImportListing.tid (#9674) 2026-02-21 17:37:37 +00:00
Jeremy Ruston
1c1f157079 More release note tweaks 2026-02-20 21:26:44 +00:00
Jeremy Ruston
ac19f300a9 Fix changenote 2026-02-20 12:05:51 +00:00
Jeremy Ruston
9012b00806 Search changenotes and impact notes (#9670)
* Tweak some changenotes

* Tweak release note tabs

* Simplify summary tab

* Remove #8702 changes/impacts

* Search change notes and impacts

* Fix release note category search

* Tweak headline changenotes
2026-02-20 12:02:14 +00:00
Jeremy Ruston
07634d6595 Merge branch 'tiddlywiki-com' 2026-02-20 09:28:07 +00:00
Saq Imtiaz
785086e0a5 Fixes ESLint errors (#9668)
* fix: apply automatic eslint fixes

* lint: allow hashbang comment for tiddlywiki.js

* lint: first back of manual lint fixes for unused vars

* lint: added more fixes for unused vars

* lint: missed files

* lint: updated eslint config with selected rules from #9669
2026-02-20 08:38:42 +00:00
IchijikuIchigo
8cd6bbc075 [ja_JP] Japanese translation update - 'Community' section of tiddlywiki.com (#9662)
* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 381388f, 4dc89f6, 5fa1098

* [ja_JP] Japanese translation update from commit: 3c1d658

* [ja_JP] Japanese translation update from commit: 3c1d658

* [ja_JP] Japanese translation update from commit: 29a567f, 6aee5eb

* [ja_JP] Japanese translation update from commit: 0ac2b6c

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 5dfdbc8

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 81d8d67

* [ja_JP] Japanese translation update from commit: 81d8d67

* [ja_JP] Japanese translation update from commit: 4196d96

* [ja_JP] Japanese translation update from commit: 1994574

* [ja_JP] Japanese translation update from commit: 1994574

* [ja-JP] Japanese translation of 'community\project\TiddlyWiki Project.tid'

* [ja-JP] Japanese translation of 'community\docs\Community Cards Caveats.tid'

* [ja-JP] Japanese translation of 'community\project\TiddlyWiki People.tid'

* [ja-JP] Japanese translation of 'community\project\Vacant Positions.tid'

* [ja-JP] Japanese translation of 'community\docs\Community Cards.tid'

* [ja-JP] Japanese translation of 'community\docs\Displaying Community Cards.tid'

* [ja-JP] Japanese translation of 'community\docs\Submitting a Community Card.tid'

* [ja-JP] Japanese translation of 'community\tools\cards\Procedures.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Resources.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Resources.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Community Links Aggregator.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\TiddlyWiki Newsletter.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\marketplace\TiddlyWiki Marketplace.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hellothere\HelloThumbnail.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Improving TiddlyWiki Documentation.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\Translate TiddlyWiki into your language.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\TiddlyWiki_European_Meetup_2016.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\TiddlyWiki_European_Meetup_2017.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Tidme by oflg.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\_Cardo-A Task and Project Management Wiki_ by David_Szego.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Drift by Tony K.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\editions\Stroll by David Gifford.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\GSD5.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\TiddlyWiki for Scholars.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\_TiddlyStudy_ by Kebi.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\Wikilabs by PMario.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\Projectify by Nicolas Petton.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\plugins\TW5-Graph by Flibbles.tid'

* [ja-JP] Japanese translation has been modified to display the ja-title.

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_A free, open source wiki revisited_ by Mark Gibbs, NetworkWorld.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_Notizen mit TiddlyWiki systemubergreifend nutzen_ by Michael Sonntag.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_Setting Up a Personal TiddlyWiki Server on OS X_ by Kris Johnson.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_TiddlyWiki 5 im Betatest_ by besim.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\articles\_TiddlyWiki_ by Sander de Boer.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\community\resources\TiddlyWiki Posts.tid'

* [ja-JP] A little correction to the Japanese translation
2026-02-15 11:56:40 +01:00
Mario Pietsch
6fc65c1560 [DOCS] Slightly Improve "How to create keyboard shortcuts" Readability (#9478) 2026-02-05 17:01:40 +01:00
Mario Pietsch
ab29f17d35 [DOCS] Add Repo-link to "Installing official plugins on Node.js" (#9483)
* [DOCS] Add Repo-link to "Installing official plugins on Node.js"

* Update Installing official plugins on Node.js.tid
2026-02-04 21:26:48 +01:00
IchijikuIchigo
5ae4770317 [ja_JP] Update of Japanese translations (#9581)
* [ja_JP] Japanese translation update from commit: 5ff4e02

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\Hire Jeremy Sidebar Segment.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\Hire Jeremy Sidebar Segment.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hire-jeremy\HireJeremy.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hellothere\thumbnails\HelloThumbnail - Community Survey.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\hellothere\thumbnails\HelloThumbnail - TW5-Graph.tid'

* [ja_JP] Japanese translation update from commit: e3af967

* [ja_JP] Japanese translation update from commit: bdc0fe1

* [ja_JP] Japanese translation update from commit: e3af967

* [ja_JP] Japanese translation update from commit: bdc0fe1, e3af967

* [ja_JP] Japanese translation update from commit: fdafdba, e3af967, ecba671, 935e89b

* [ja_JP] Japanese translation update from commit: bdc0fe1, e3af967

* [ja_JP] Japanese translation update from commit: 0763ee5

* [ja_JP] Japanese translation update from commit: bdc0fe1

* [ja_JP] Japanese translation update from commit: b0d950f, 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: b0d950f, 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: 4dc89f6

* [ja_JP] Japanese translation update from commit: b0d950f

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\Commands.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\BuildCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\ClearPasswordCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\CommandsCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\DeleteTiddlersCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\EditionsCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\FetchCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\HelpCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\ImportCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\InitCommand.tid'

* [ja-JP] Japanese translation of 'editions\ja-JP\tiddlers\commands\ListenCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\LoadCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\MakeLibraryCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\OutputCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\PasswordCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\RenderCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\SaveCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\SaveWikiFolderCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\SetFieldCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\UnpackPluginCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\VerboseCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\VersionCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\RenderTiddlerCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\RenderTiddlersCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\SaveTiddlerCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\SaveTiddlersCommand.tid'

* [ja-JP] Japanese translation of 'editions\tw5.com\tiddlers\commands\ServerCommand.tid'
2026-02-04 21:24:55 +01:00
609 changed files with 9910 additions and 4733 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,8 +20,7 @@ var Command = function(params,commander) {
}; };
Command.prototype.execute = function() { 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 // 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))) { if($tw.boot.wikiTiddlersPath || ($tw.utils.isDirectory($tw.boot.wikiPath) && !$tw.utils.isDirectoryEmpty($tw.boot.wikiPath))) {
return "Wiki folder is not empty"; return "Wiki folder is not empty";

View File

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

View File

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

View File

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

View File

@@ -7,59 +7,57 @@ Render individual tiddlers and save the results to the specified files
\*/ \*/
"use strict"; "use strict";
var widget = require("$:/core/modules/widgets/widget.js"); exports.info = {
name: "render",
synchronous: true
};
exports.info = { var Command = function(params,commander,callback) {
name: "render", this.params = params;
synchronous: true this.commander = commander;
}; this.callback = callback;
};
var Command = function(params,commander,callback) { Command.prototype.execute = function() {
this.params = params; if(this.params.length < 1) {
this.commander = commander; return "Missing tiddler filter";
this.callback = callback; }
}; var self = this,
fs = require("fs"),
Command.prototype.execute = function() { path = require("path"),
if(this.params.length < 1) { wiki = this.commander.wiki,
return "Missing tiddler filter"; 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 self = this, });
fs = require("fs"), return null;
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,8 +9,6 @@ Command to render several tiddlers to a folder of files
"use strict"; "use strict";
var widget = require("$:/core/modules/widgets/widget.js");
exports.info = { exports.info = {
name: "rendertiddlers", name: "rendertiddlers",
synchronous: true synchronous: true

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,22 +9,22 @@ Base64 UTF-8 utlity functions.
"use strict"; "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) { function base64ToBytes(base64) {
const binString = exports.atob(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) { 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); 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,8 +16,7 @@ ignoreEnvironmentVariables: defaults to false
*/ */
exports.getAllPlugins = function(options) { exports.getAllPlugins = function(options) {
options = options || {}; options = options || {};
var fs = require("fs"), var path = require("path"),
path = require("path"),
tiddlers = {}; tiddlers = {};
// Collect up the library plugins // Collect up the library plugins
var collectPlugins = function(folder) { var collectPlugins = function(folder) {

View File

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

View File

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

View File

@@ -2,6 +2,9 @@
title: $:/core/modules/deserializers.js title: $:/core/modules/deserializers.js
type: application/javascript type: application/javascript
module-type: tiddlerdeserializer module-type: tiddlerdeserializer
Functions to deserialise tiddlers from a block of text
\*/ \*/
"use strict"; "use strict";
@@ -34,6 +37,12 @@ exports["application/json"] = function(text,fields) {
return results; 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) { exports["text/html"] = function(text,fields) {
var results = []; var results = [];
// Check if we've got an old-style store area // Check if we've got an old-style store area
@@ -51,11 +60,11 @@ exports["text/html"] = function(text,fields) {
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields)); results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text); newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
} }
// Return if we had either an old-style or a new-style store area
if(storeAreaMatch || haveHadNewStoreArea) { if(storeAreaMatch || haveHadNewStoreArea) {
return results; return results;
} }
// Otherwise, check whether we've got an encrypted file
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text); var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
if(encryptedStoreArea) { if(encryptedStoreArea) {
// If so, attempt to decrypt it using the current password // If so, attempt to decrypt it using the current password
@@ -115,18 +124,30 @@ function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
return results; return results;
} }
var deserializeTiddlerDiv = function(text) { /*
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] */) {
// Slot together the default results // Slot together the default results
var result = {}; var result = {};
if(arguments.length > 1) { if(arguments.length > 1) {
for(var f=1; f<arguments.length; f++) { for(var f=1; f<arguments.length; f++) {
var fields = arguments[f]; var fields = arguments[f];
for(var t in fields) { 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, var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
endRegExp, endRegExp,
match = startRegExp.exec(text); match = startRegExp.exec(text);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,6 +2,9 @@
title: $:/core/modules/filter-tracker.js title: $:/core/modules/filter-tracker.js
type: application/javascript type: application/javascript
module-type: global module-type: global
Class to track the results of a filter string
\*/ \*/
"use strict"; "use strict";
@@ -18,6 +21,14 @@ class FilterTracker {
this.processChanges(changes); 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 = {}) { track(options = {}) {
const { const {
filterString, filterString,
@@ -58,17 +69,17 @@ class FilterTracker {
if(!tracker) return; if(!tracker) return;
const results = []; const results = [];
// Evaluate the filter and remove duplicate 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); $tw.utils.pushTop(results, title);
}); });
// Process the newly entered results // Process the newly entered results
results.forEach(title => { results.forEach((title) => {
if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) { if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) {
tracker.resultValues[title] = tracker.fnEnter(title) || true; tracker.resultValues[title] = tracker.fnEnter(title) || true;
} }
}); });
// Process the results that have just left // Process the results that have just left
tracker.previousResults.forEach(title => { tracker.previousResults.forEach((title) => {
if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) { if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) {
tracker.fnLeave(title, tracker.resultValues[title]); tracker.fnLeave(title, tracker.resultValues[title]);
delete tracker.resultValues[title]; delete tracker.resultValues[title];
@@ -80,7 +91,7 @@ class FilterTracker {
processChanges(changes) { processChanges(changes) {
for(const tracker of this.trackers.values()) { 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) { if(title && tracker.previousResults.includes(title) && tracker.fnChange) {
tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title]; tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title];
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,18 @@
title: $:/core/modules/filters/addprefix.js title: $:/core/modules/filters/addprefix.js
type: application/javascript type: application/javascript
module-type: filteroperator 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"; "use strict";
/*
Export our filter function
*/
exports.addprefix = function(source,operator,options) { exports.addprefix = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {

View File

@@ -2,10 +2,18 @@
title: $:/core/modules/filters/addsuffix.js title: $:/core/modules/filters/addsuffix.js
type: application/javascript type: application/javascript
module-type: filteroperator 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"; "use strict";
/*
Export our filter function
*/
exports.addsuffix = function(source,operator,options) { exports.addsuffix = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,14 +2,21 @@
title: $:/core/modules/filters/each.js title: $:/core/modules/filters/each.js
type: application/javascript type: application/javascript
module-type: filteroperator 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"; "use strict";
/*
Export our filter function
*/
exports.each = function(source,operator,options) { exports.each = function(source,operator,options) {
var results =[] , var results =[] ,
value,values = {}, value,values = {},
field = operator.operand || "title"; field = operator.operand || "title";
if(operator.suffix === "value" && field === "title") { if(operator.suffix === "value" && field === "title") {
source(function(tiddler,title) { source(function(tiddler,title) {
if(!$tw.utils.hop(values,title)) { if(!$tw.utils.hop(values,title)) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/getvariable.js title: $:/core/modules/filters/getvariable.js
type: application/javascript type: application/javascript
module-type: filteroperator 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"; "use strict";
/*
Export our filter function
*/
exports.getvariable = function(source,operator,options) { exports.getvariable = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {

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