1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-20 00:49:50 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Jeremy Ruston
88619fc215 Add changenote 2025-12-29 21:09:17 +00:00
Jeremy Ruston
dfc5e9e6e5 Initial Commit 2025-12-29 21:01:38 +00:00
726 changed files with 8452 additions and 7575 deletions

View File

@@ -1,62 +0,0 @@
---
name: Bug report
about: Create a report to help us improve TiddlyWiki 5
title: "[Report] "
type: report
---
<!-- Remove elements, that you do not need -->
<!-- Add screenshots where needed -->
**Problem Description**
<!-- Describe your problem: A clear and concise description of what your problem is -->
**To Reproduce**
Steps to reproduce the behavior:
1. At https://tiddlywiki.com
2. Click on ...
3. Scroll down to ...
4. See ...
**Expected behavior**
As a user,
<!-- As a developer, -->
I would expect ...
**TiddlyWiki Configuration**
<!-- Please complete the following information -->
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
<!-- Your report comes here -->
<!-- or -->
<!-- Add it manually -->
- Version: <!-- e.g. v5.3.8 -->
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
**Desktop**
<!-- Please complete the following information -->
- OS: <!-- e.g. iOS -->
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
**Smartphone**
<!-- Please complete the following information -->
- Device: <!-- e.g. iPhone6 -->
- OS: <!-- e.g. iOS8.1 -->
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
**Additional context**
<!-- Add any other context about the problem here. -->

68
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,68 @@
name: Bug report
description: Create a report to help us improve TiddlyWiki 5
title: "[BUG] "
type: bug
body:
- type: textarea
id: Describe
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: Expected
attributes:
label: Expected behavior
description: A clear and concise description of what you expected to happen.
validations:
required: false
- type: textarea
id: Reproduce
attributes:
label: To Reproduce
description: "Steps to reproduce the behavior:"
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: false
- type: textarea
id: Screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
placeholder: Drag image here to upload screenshot!
validations:
required: false
- type: textarea
id: Configuration
attributes:
label: TiddlyWiki Configuration
description: please complete the following information
placeholder: |
- Version [e.g. v5.1.24]
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
- Plugins installed [e.g. Freelinks, TiddlyMap]
### Desktop (please complete the following information):
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
### Smartphone (please complete the following information):
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
validations:
required: true
- type: textarea
id: Context
attributes:
label: Additional context
description: Add any other context about the problem here.

View File

@@ -4,23 +4,18 @@ about: Suggest an idea for TiddlyWiki 5
title: "[IDEA]" title: "[IDEA]"
labels: '' labels: ''
assignees: '' assignees: ''
type: idea type: feature
--- ---
**Is your idea related to a problem? Please describe.** **Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is. Eg:
As a user, I would like [...]
**Describe the solution you'd like** **Describe the solution you'd like**
A clear and concise description of what you want to happen. A clear and concise description of what you want to happen.
**Describe alternatives you've considered** **Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered. A clear and concise description of any alternative solutions or features you've considered.
**Additional context** **Additional context**
Add any other context or screenshots about the feature request here. Add any other context or screenshots about the feature request here.

View File

@@ -120,6 +120,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|| exit 1 || exit 1
# /empty.html Empty # /empty.html Empty
# /empty.hta For Internet Explorer
# /empty-external-core.html External core empty # /empty-external-core.html External core empty
# /tiddlywikicore-<version>.js Core plugin javascript # /tiddlywikicore-<version>.js Core plugin javascript
node $TW5_BUILD_TIDDLYWIKI \ node $TW5_BUILD_TIDDLYWIKI \

View File

@@ -316,25 +316,8 @@ $tw.utils.htmlDecode = function(s) {
return s.toString().replace(/&lt;/mg,"<").replace(/&nbsp;/mg,"\xA0").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&"); return s.toString().replace(/&lt;/mg,"<").replace(/&nbsp;/mg,"\xA0").replace(/&gt;/mg,">").replace(/&quot;/mg,"\"").replace(/&amp;/mg,"&");
}; };
/* /** @deprecated Use window.location.hash instead. */
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash) $tw.utils.getLocationHash = () => window.location.hash;
*/
$tw.utils.getLocationHash = function() {
const href = window.location.href,
idx = href.indexOf("#");
if(idx === -1) {
return "#";
}
const afterHash = href.substring(idx + 1);
if(afterHash.startsWith("#") || afterHash.startsWith("%23")) {
// Special case: ignore location hash if it itself starts with a #
return "#";
}
return href.substring(idx);
};
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */ /** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
$tw.utils.pad = function(value,length = 2) { $tw.utils.pad = function(value,length = 2) {
@@ -613,7 +596,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
// Compile the code into a function // Compile the code into a function
var fn; var fn;
if($tw.browser) { if($tw.browser) {
fn = Function("return " + code + "\n\n//# sourceURL=" + filename)(); // See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839 fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- 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)

View File

@@ -33,8 +33,8 @@ exports.handler = function(request,response,state) {
} }
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}}); var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
var headers = {"Content-Type": renderType}; // Naughty not to set a content-type, but it's the easiest way to ensure the browser will see HTML pages as HTML, and accept plain text tiddlers as CSS or JS
state.sendResponse(200,headers,text,"utf8"); state.sendResponse(200,{},text,"utf8");
} else { } else {
response.writeHead(404); response.writeHead(404);
response.end(); response.end();

View File

@@ -42,8 +42,6 @@ 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
this.corsEnable = this.get("cors-enable") === "yes";
// Initialise CSRF // Initialise CSRF
this.csrfDisable = this.get("csrf-disable") === "yes"; this.csrfDisable = this.get("csrf-disable") === "yes";
// Initialize Gzip compression // Initialize Gzip compression
@@ -263,13 +261,6 @@ Server.prototype.requestHandler = function(request,response,options) {
state.urlInfo = url.parse(request.url); state.urlInfo = url.parse(request.url);
state.queryParameters = querystring.parse(state.urlInfo.query); state.queryParameters = querystring.parse(state.urlInfo.query);
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || ""; state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
// Enable CORS
if(this.corsEnable) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Expose-Headers", "*");
}
state.sendResponse = sendResponse.bind(self,request,response); state.sendResponse = sendResponse.bind(self,request,response);
// Get the principals authorized to access this resource // Get the principals authorized to access this resource
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers"; state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
@@ -294,12 +285,6 @@ Server.prototype.requestHandler = function(request,response,options) {
response.end(); response.end();
return; return;
} }
// Reply to OPTIONS
if(this.corsEnable && request.method === "OPTIONS") {
response.writeHead(204);
response.end();
return;
}
// Find the route that matches this path // Find the route that matches this path
var route = self.findMatchingRoute(request,state); var route = self.findMatchingRoute(request,state);
// Optionally output debug info // Optionally output debug info

View File

@@ -1,30 +0,0 @@
/*\
title: $:/core-modules/modules/utils/base64.js
type: application/javascript
module-type: utils-node
Base64 UTF-8 utlity functions.
\*/
"use strict";
const{ TextEncoder, TextDecoder } = require("node:util");
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
function base64ToBytes(base64) {
const binString = exports.atob(base64);
return Uint8Array.from(binString, m => m.codePointAt(0));
};
function bytesToBase64(bytes) {
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
return exports.btoa(binString);
};
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));

View File

@@ -1,95 +0,0 @@
/*\
title: $:/core-server/modules/utils/escapecss.js
type: application/javascript
module-type: utils-node
Provides CSS.escape() functionality.
\*/
"use strict";
exports.escapeCSS = (function() {
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
/* eslint-disable */
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
return function(value) {
if (arguments.length == 0) {
throw new TypeError('`CSS.escape` requires an argument.');
}
var string = String(value);
var length = string.length;
var index = -1;
var codeUnit;
var result = '';
var firstCodeUnit = string.charCodeAt(0);
while (++index < length) {
codeUnit = string.charCodeAt(index);
// Note: theres no need to special-case astral symbols, surrogate
// pairs, or lone surrogates.
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
// (U+FFFD).
if (codeUnit == 0x0000) {
result += '\uFFFD';
continue;
}
if (
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
// U+007F, […]
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
// If the character is the first character and is in the range [0-9]
// (U+0030 to U+0039), […]
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
// If the character is the second character and is in the range [0-9]
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
(
index == 1 &&
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
firstCodeUnit == 0x002D
)
) {
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
result += '\\' + codeUnit.toString(16) + ' ';
continue;
}
if (
// If the character is the first character and is a `-` (U+002D), and
// there is no second character, […]
index == 0 &&
length == 1 &&
codeUnit == 0x002D
) {
result += '\\' + string.charAt(index);
continue;
}
// If the character is not handled by one of the above rules and is
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
// U+005A), or [a-z] (U+0061 to U+007A), […]
if (
codeUnit >= 0x0080 ||
codeUnit == 0x002D ||
codeUnit == 0x005F ||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
codeUnit >= 0x0061 && codeUnit <= 0x007A
) {
// the character itself
result += string.charAt(index);
continue;
}
// Otherwise, the escaped character.
// https://drafts.csswg.org/cssom/#escape-a-character
result += '\\' + string.charAt(index);
}
return result;
};
/* eslint-enable */
})();

View File

@@ -5,4 +5,3 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]] * [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]] * [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]] * [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
* [[diff-match-patch-es by antfu|https://github.com/antfu/diff-match-patch-es]]

View File

@@ -6,7 +6,6 @@ Appearance/Caption: Appearance
Appearance/Hint: Ways to customise the appearance of your TiddlyWiki. Appearance/Hint: Ways to customise the appearance of your TiddlyWiki.
Basics/AnimDuration/Prompt: Animation duration Basics/AnimDuration/Prompt: Animation duration
Basics/AutoFocus/Prompt: Default focus field for new tiddlers Basics/AutoFocus/Prompt: Default focus field for new tiddlers
Basics/AutoFocusEdit/Prompt: Default focus field for existing tiddlers
Basics/Caption: Basics Basics/Caption: Basics
Basics/DefaultTiddlers/BottomHint: Use &#91;&#91;double square brackets&#93;&#93; for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}} Basics/DefaultTiddlers/BottomHint: Use &#91;&#91;double square brackets&#93;&#93; for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}}
Basics/DefaultTiddlers/Prompt: Default tiddlers Basics/DefaultTiddlers/Prompt: Default tiddlers

View File

@@ -1,4 +0,0 @@
title: $:/language/Draft/
Attribution: Draft of '<<draft-title>>' by {{$:/status/UserName}}
Title: Draft of '<<draft-title>>'

View File

@@ -1,6 +1,5 @@
title: $:/language/ title: $:/language/
Alerts: Alerts
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected: AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
BinaryWarning/Prompt: This tiddler contains binary data BinaryWarning/Prompt: This tiddler contains binary data
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details. ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.

View File

@@ -9,11 +9,6 @@ Advanced/ShadowInfo/NotShadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text
Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler
Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link> Advanced/ShadowInfo/Shadow/Source: It is defined in the plugin <$link to=<<pluginTiddler>>><$text text=<<pluginTiddler>>/></$link>
Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler Advanced/ShadowInfo/OverriddenShadow/Hint: It is overridden by an ordinary tiddler
Advanced/CascadeInfo/Heading: Cascade Details
Advanced/CascadeInfo/Hint: These are the view template segments (tagged <<tag "$:/tags/ViewTemplate">>) using a cascade filter and their resulting template for the current tiddler.
Advanced/CascadeInfo/Detail/View: View
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Active cascade filter
Advanced/CascadeInfo/Detail/Template: Template
Fields/Caption: Fields Fields/Caption: Fields
List/Caption: List List/Caption: List
List/Empty: This tiddler does not have a list List/Empty: This tiddler does not have a list

View File

@@ -1,106 +0,0 @@
/*\
title: $:/core/modules/background-actions.js
type: application/javascript
module-type: global
\*/
"use strict";
class BackgroundActionDispatcher {
constructor(filterTracker, wiki) {
this.filterTracker = filterTracker;
this.wiki = wiki;
this.nextTrackedFilterId = 1;
this.trackedFilters = new Map(); // Use Map for better key management
this.filterTracker.track({
filterString: "[all[tiddlers+shadows]tag[$:/tags/BackgroundAction]!is[draft]]",
fnEnter: title => this.trackFilter(title),
fnLeave: (title, enterValue) => this.untrackFilter(enterValue),
fnChange: (title, enterValue) => {
this.untrackFilter(enterValue);
return this.trackFilter(title);
},
fnProcess: changes => this.process(changes)
});
}
trackFilter(title) {
const tiddler = this.wiki.getTiddler(title);
const id = this.nextTrackedFilterId++;
const tracker = new BackgroundActionTracker({
wiki: this.wiki,
title,
trackFilter: tiddler.fields["track-filter"],
actions: tiddler.fields.text
});
this.trackedFilters.set(id, tracker);
return id;
}
untrackFilter(enterValue) {
const tracker = this.trackedFilters.get(enterValue);
if(tracker) {
tracker.destroy();
}
this.trackedFilters.delete(enterValue);
}
process(changes) {
for(const tracker of this.trackedFilters.values()) {
tracker.process(changes);
}
}
}
class BackgroundActionTracker {
constructor({wiki, title, trackFilter, actions}) {
this.wiki = wiki;
this.title = title;
this.trackFilter = trackFilter;
this.actions = actions;
this.filterTracker = new $tw.FilterTracker(this.wiki);
this.hasChanged = false;
this.trackerID = this.filterTracker.track({
filterString: this.trackFilter,
fnEnter: () => { this.hasChanged = true; },
fnLeave: () => { this.hasChanged = true; },
fnProcess: changes => {
if(this.hasChanged) {
this.hasChanged = false;
console.log("Processing background action", this.title);
const tiddler = this.wiki.getTiddler(this.title);
let doActions = true;
if(tiddler && tiddler.fields.platforms) {
doActions = false;
const platforms = $tw.utils.parseStringArray(tiddler.fields.platforms);
if(($tw.browser && platforms.includes("browser")) || ($tw.node && platforms.includes("node"))) {
doActions = true;
}
}
if(doActions) {
this.wiki.invokeActionString(
this.actions,
null,
{
currentTiddler: this.title
},{
parentWidget: $tw.rootWidget
}
);
}
}
}
});
}
process(changes) {
this.filterTracker.handleChangeEvent(changes);
}
destroy() {
this.filterTracker.untrack(this.trackerID);
}
}
exports.BackgroundActionDispatcher = BackgroundActionDispatcher;

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,12 +184,18 @@ 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;
@@ -180,11 +204,17 @@ FramedEngine.prototype.handleKeydownEvent = function(event) {
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";
@@ -44,8 +48,8 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
this.toolbarNode = this.document.createElement("div"); this.toolbarNode = this.document.createElement("div");
this.toolbarNode.className = "tc-editor-toolbar"; this.toolbarNode.className = "tc-editor-toolbar";
parent.insertBefore(this.toolbarNode,nextSibling); parent.insertBefore(this.toolbarNode,nextSibling);
this.domNodes.push(this.toolbarNode);
this.renderChildren(this.toolbarNode,null); this.renderChildren(this.toolbarNode,null);
this.domNodes.push(this.toolbarNode);
} }
// Create our element // Create our element
var editInfo = this.getEditInfo(), var editInfo = this.getEditInfo(),
@@ -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,6 +211,9 @@ 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
@@ -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) {
@@ -256,17 +282,20 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
} }
} }
} }
// 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,6 +2,9 @@
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";

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,
@@ -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

@@ -1,95 +0,0 @@
/*\
title: $:/core/modules/filter-tracker.js
type: application/javascript
module-type: global
\*/
"use strict";
class FilterTracker {
constructor(wiki) {
this.wiki = wiki;
this.trackers = new Map();
this.nextTrackerId = 1;
}
handleChangeEvent(changes) {
this.processTrackers();
this.processChanges(changes);
}
track(options = {}) {
const {
filterString,
fnEnter,
fnLeave,
fnChange,
fnProcess
} = options;
const id = this.nextTrackerId++;
const tracker = {
id,
filterString,
fnEnter,
fnLeave,
fnChange,
fnProcess,
previousResults: [],
resultValues: {}
};
this.trackers.set(id, tracker);
// Process the tracker
this.processTracker(id);
return id;
}
untrack(id) {
this.trackers.delete(id);
}
processTrackers() {
for(const id of this.trackers.keys()) {
this.processTracker(id);
}
}
processTracker(id) {
const tracker = this.trackers.get(id);
if(!tracker) return;
const results = [];
// Evaluate the filter and remove duplicate results
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), title => {
$tw.utils.pushTop(results, title);
});
// Process the newly entered results
results.forEach(title => {
if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) {
tracker.resultValues[title] = tracker.fnEnter(title) || true;
}
});
// Process the results that have just left
tracker.previousResults.forEach(title => {
if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) {
tracker.fnLeave(title, tracker.resultValues[title]);
delete tracker.resultValues[title];
}
});
// Update the previous results
tracker.previousResults = results;
}
processChanges(changes) {
for(const tracker of this.trackers.values()) {
Object.keys(changes).forEach(title => {
if(title && tracker.previousResults.includes(title) && tracker.fnChange) {
tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title];
}
});
if(tracker.fnProcess) {
tracker.fnProcess(changes);
}
}
}
}
exports.FilterTracker = FilterTracker;

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) {
@@ -21,7 +24,7 @@ exports.cascade = function(operationSubFunction,options) {
} }
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}) "..currentTiddler": widget.getVariable("currentTiddler","")
})); }));
if(output.length !== 0) { if(output.length !== 0) {
result = output[0]; result = output[0];

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) {
@@ -14,7 +18,7 @@ exports.filter = function(operationSubFunction,options) {
results.each(function(title) { results.each(function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}), "..currentTiddler": widget.getVariable("currentTiddler",""),
"index": "" + index, "index": "" + index,
"revIndex": "" + (results.length - 1 - index), "revIndex": "" + (results.length - 1 - index),
"length": "" + results.length "length": "" + results.length

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,18 @@
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
\*/ \*/
/*jslint node: true, browser: true */
/*global $tw: false */
"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 +30,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) {
@@ -17,7 +20,7 @@ exports.map = function(operationSubFunction,options) {
$tw.utils.each(inputTitles,function(title) { $tw.utils.each(inputTitles,function(title) {
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}), "..currentTiddler": widget.getVariable("currentTiddler",""),
"index": "" + index, "index": "" + index,
"revIndex": "" + (inputTitles.length - 1 - index), "revIndex": "" + (inputTitles.length - 1 - index),
"length": "" + inputTitles.length "length": "" + inputTitles.length

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) {
@@ -14,7 +17,7 @@ exports.reduce = function(operationSubFunction,options) {
results.each(function(title) { results.each(function(title) {
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}), "..currentTiddler": widget.getVariable("currentTiddler"),
"index": "" + index, "index": "" + index,
"revIndex": "" + (results.length - 1 - index), "revIndex": "" + (results.length - 1 - index),
"length": "" + results.length, "length": "" + results.length,

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) {
@@ -20,7 +24,7 @@ exports.sort = function(operationSubFunction,options) {
results.each(function(title) { results.each(function(title) {
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({ var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}) "..currentTiddler": widget.getVariable("currentTiddler")
})); }));
sortKeys.push(key[0] || ""); sortKeys.push(key[0] || "");
}); });
@@ -29,7 +33,7 @@ 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]);

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";
@@ -44,12 +55,12 @@ 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";
} }
@@ -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 {
@@ -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]}]}
@@ -217,9 +232,19 @@ exports.getFilterRunPrefixes = function() {
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); try {
const fnResult = fn.call(this,source,widget);
return fnResult;
} catch(e) {
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
}
}; };
/*
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 +262,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 +307,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 +319,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 +365,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 +407,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";

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

@@ -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,10 +2,17 @@
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 = {},

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";

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,
@@ -22,13 +28,13 @@ 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
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 = [],
@@ -13,7 +19,7 @@ exports.filter = function(source,operator,options) {
source(function(tiddler,title) { source(function(tiddler,title) {
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({ var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
"currentTiddler": "" + title, "currentTiddler": "" + title,
"..currentTiddler": options.widget.getVariable("currentTiddler",{defaultValue:""}) "..currentTiddler": options.widget.getVariable("currentTiddler","")
})); }));
if((list.length > 0) === target) { if((list.length > 0) === target) {
results.push(title); results.push(title);

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,6 +6,9 @@ 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) {

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,10 +2,16 @@
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,title,results = [];
if(operator.operand){ if(operator.operand){

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) {

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/has.js title: $:/core/modules/filters/has.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Filter operator for checking if a tiddler has the specified field or index
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.has = function(source,operator,options) { exports.has = function(source,operator,options) {
var results = [], var results = [],
invert = operator.prefix === "!"; invert = operator.prefix === "!";

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/haschanged.js title: $:/core/modules/filters/haschanged.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Filter operator returns tiddlers from the list that have a non-zero changecount.
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.haschanged = function(source,operator,options) { exports.haschanged = function(source,operator,options) {
var results = []; var results = [];
if(operator.prefix === "!") { if(operator.prefix === "!") {

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/indexes.js title: $:/core/modules/filters/indexes.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Filter operator for returning the indexes of a data tiddler
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.indexes = function(source,operator,options) { exports.indexes = 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/insertafter.js title: $:/core/modules/filters/insertafter.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Insert an item after another item in a list
\*/ \*/
"use strict"; "use strict";
/*
Order a list
*/
exports.insertafter = function(source,operator,options) { exports.insertafter = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
@@ -18,7 +24,7 @@ exports.insertafter = function(source,operator,options) {
if(pos !== -1) { if(pos !== -1) {
results.splice(pos,1); results.splice(pos,1);
} }
// Insert the entry after the target marker
pos = results.indexOf(target); pos = results.indexOf(target);
if(pos !== -1) { if(pos !== -1) {
results.splice(pos+1,0,operator.operand); results.splice(pos+1,0,operator.operand);

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/insertbefore.js title: $:/core/modules/filters/insertbefore.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Insert an item before another item in a list
\*/ \*/
"use strict"; "use strict";
/*
Order a list
*/
exports.insertbefore = function(source,operator,options) { exports.insertbefore = function(source,operator,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
@@ -18,7 +24,7 @@ exports.insertbefore = function(source,operator,options) {
if(pos !== -1) { if(pos !== -1) {
results.splice(pos,1); results.splice(pos,1);
} }
// Insert the entry before the target marker
pos = results.indexOf(target); pos = results.indexOf(target);
if(pos !== -1) { if(pos !== -1) {
results.splice(pos,0,operator.operand); results.splice(pos,0,operator.operand);

View File

@@ -2,6 +2,9 @@
title: $:/core/modules/filters/is.js title: $:/core/modules/filters/is.js
type: application/javascript type: application/javascript
module-type: filteroperator module-type: filteroperator
Filter operator for checking tiddler properties
\*/ \*/
"use strict"; "use strict";
@@ -16,6 +19,9 @@ function getIsFilterOperators() {
return isFilterOperators; return isFilterOperators;
} }
/*
Export our filter function
*/
exports.is = function(source,operator,options) { exports.is = function(source,operator,options) {
// Dispatch to the correct isfilteroperator // Dispatch to the correct isfilteroperator
var isFilterOperators = getIsFilterOperators(); var isFilterOperators = getIsFilterOperators();

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/is/binary.js title: $:/core/modules/filters/is/binary.js
type: application/javascript type: application/javascript
module-type: isfilteroperator module-type: isfilteroperator
Filter function for [is[binary]]
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.binary = function(source,prefix,options) { exports.binary = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/is/blank.js title: $:/core/modules/filters/is/blank.js
type: application/javascript type: application/javascript
module-type: isfilteroperator module-type: isfilteroperator
Filter function for [is[blank]]
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.blank = function(source,prefix,options) { exports.blank = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {

View File

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

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/is/draft.js title: $:/core/modules/filters/is/draft.js
type: application/javascript type: application/javascript
module-type: isfilteroperator module-type: isfilteroperator
Filter function for [is[draft]] analagous to [has[draft.of]]
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.draft = function(source,prefix,options) { exports.draft = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/is/image.js title: $:/core/modules/filters/is/image.js
type: application/javascript type: application/javascript
module-type: isfilteroperator module-type: isfilteroperator
Filter function for [is[image]]
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.image = function(source,prefix,options) { exports.image = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {

View File

@@ -2,10 +2,16 @@
title: $:/core/modules/filters/is/missing.js title: $:/core/modules/filters/is/missing.js
type: application/javascript type: application/javascript
module-type: isfilteroperator module-type: isfilteroperator
Filter function for [is[missing]]
\*/ \*/
"use strict"; "use strict";
/*
Export our filter function
*/
exports.missing = function(source,prefix,options) { exports.missing = function(source,prefix,options) {
var results = []; var results = [];
if(prefix === "!") { if(prefix === "!") {

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