1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2026-02-23 02:19: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
780 changed files with 7863 additions and 12225 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

@@ -20,7 +20,7 @@ jobs:
steps: steps:
- name: build-size-check - name: build-size-check
id: get_sizes id: get_sizes
uses: TiddlyWiki/cerebrus@v7 uses: TiddlyWiki/cerebrus@v6
with: with:
pr_number: ${{ github.event.pull_request.number }} pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }} repo: ${{ github.repository }}

View File

@@ -25,7 +25,7 @@ jobs:
steps: steps:
- name: Build and check size - name: Build and check size
uses: TiddlyWiki/cerebrus@v7 uses: TiddlyWiki/cerebrus@v6
with: with:
pr_number: ${{ inputs.pr_number }} pr_number: ${{ inputs.pr_number }}
repo: ${{ github.repository }} repo: ${{ github.repository }}

View File

@@ -26,7 +26,7 @@ jobs:
# Step 2: Validate change notes # Step 2: Validate change notes
- name: Validate Change Notes - name: Validate Change Notes
uses: TiddlyWiki/cerebrus@v7 uses: TiddlyWiki/cerebrus@v6
with: with:
pr_number: ${{ github.event.pull_request.number }} pr_number: ${{ github.event.pull_request.number }}
repo: ${{ github.repository }} repo: ${{ github.repository }}

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

View File

@@ -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,116 +0,0 @@
/*\
title: $:/core/modules/background-actions.js
type: application/javascript
module-type: global
Class to dispatch actions when filters change
\*/
"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
// Track the filter for the background actions
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);
}
}
}
/*
Represents an individual tracked filter. Options include:
wiki: wiki to use
title: title of the tiddler being tracked
trackFilter: filter string to track changes
actions: actions to be executed when the filter changes
*/
class BackgroundActionTracker {
constructor({wiki, title, trackFilter, actions}) {
this.wiki = wiki;
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

@@ -197,7 +197,7 @@ FramedEngine.prototype.handleFocusEvent = function(event) {
Handle a keydown event 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;
} }

View File

@@ -48,19 +48,19 @@ 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(),
Engine = this.editShowToolbar ? toolbarEngine : nonToolbarEngine; Engine = this.editShowToolbar ? toolbarEngine : nonToolbarEngine;
this.engine = new Engine({ this.engine = new Engine({
widget: this, widget: this,
value: editInfo.value, value: editInfo.value,
type: editInfo.type, type: editInfo.type,
parentNode: parent, parentNode: parent,
nextSibling: nextSibling nextSibling: nextSibling
}); });
// Call the postRender hook // Call the postRender hook
if(this.postRender) { if(this.postRender) {
this.postRender(); this.postRender();
@@ -220,7 +220,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) { if(changedAttributes.tiddler || changedAttributes.field || changedAttributes.index || changedAttributes["default"] || changedAttributes["class"] || changedAttributes.placeholder || changedAttributes.size || changedAttributes.autoHeight || changedAttributes.minHeight || changedAttributes.focusPopup || changedAttributes.rows || changedAttributes.tabindex || changedAttributes.cancelPopups || changedAttributes.inputActions || changedAttributes.refreshTitle || changedAttributes.autocomplete || changedTiddlers[HEIGHT_MODE_TITLE] || changedTiddlers[ENABLE_TOOLBAR_TITLE] || changedTiddlers["$:/palette"] || changedAttributes.disabled || changedAttributes.fileDrop) {
this.refreshSelf(); this.refreshSelf();
return true; return true;
} else if(changedTiddlers[this.editRefreshTitle]) { } else if (changedTiddlers[this.editRefreshTitle]) {
this.engine.updateDomNodeText(this.getEditInfo().value); this.engine.updateDomNodeText(this.getEditInfo().value);
} else if(changedTiddlers[this.editTitle]) { } else if(changedTiddlers[this.editTitle]) {
var editInfo = this.getEditInfo(); var editInfo = this.getEditInfo();
@@ -274,8 +274,8 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
}); });
if($tw.keyboardManager.checkKeyDescriptors(event,keyInfoArray)) { if($tw.keyboardManager.checkKeyDescriptors(event,keyInfoArray)) {
var clickEvent = this.document.createEvent("Events"); var clickEvent = this.document.createEvent("Events");
clickEvent.initEvent("click",true,false); clickEvent.initEvent("click",true,false);
el.dispatchEvent(clickEvent); el.dispatchEvent(clickEvent);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
return true; return true;

View File

@@ -10,7 +10,7 @@ Text editor operation to excise the selection to a new tiddler
"use strict"; "use strict";
function isMarkdown(mediaType) { function isMarkdown(mediaType) {
return mediaType === "text/markdown" || mediaType === "text/x-markdown"; return mediaType === 'text/markdown' || mediaType === 'text/x-markdown';
} }
exports["excise"] = function(event,operation) { exports["excise"] = function(event,operation) {

View File

@@ -19,7 +19,7 @@ exports["wrap-lines"] = function(event,operation) {
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 // Replace with selection

View File

@@ -44,7 +44,7 @@ exports["wrap-selection"] = function(event,operation) {
break; break;
} }
return result; return result;
}; }
function togglePrefixSuffix() { function togglePrefixSuffix() {
if(o.text.substring(o.selStart - prefix.length, o.selStart + suffix.length) === prefix + suffix) { if(o.text.substring(o.selStart - prefix.length, o.selStart + suffix.length) === prefix + suffix) {

View File

@@ -1,106 +0,0 @@
/*\
title: $:/core/modules/filter-tracker.js
type: application/javascript
module-type: global
Class to track the results of a filter string
\*/
"use strict";
class FilterTracker {
constructor(wiki) {
this.wiki = wiki;
this.trackers = new Map();
this.nextTrackerId = 1;
}
handleChangeEvent(changes) {
this.processTrackers();
this.processChanges(changes);
}
/*
Add a tracker to the filter tracker. Returns null if any of the parameters are invalid, or a tracker id if the tracker was added successfully. Options include:
filterString: the filter string to track
fnEnter: function to call when a title enters the filter results. Called even if the tiddler does not actually exist. Called as (title), and should return a truthy value that is stored in the tracker as the "enterValue"
fnLeave: function to call when a title leaves the filter results. Called as (title,enterValue)
fnChange: function to call when a tiddler changes in the filter results. Only called for filter results that identify a tiddler or shadow tiddler. Called as (title,enterValue), and may optionally return a replacement enterValue
fnProcess: function to call each time the tracker is processed, after any enter, leave or change functions are called. Called as (changes)
*/
track(options = {}) {
const {
filterString,
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

@@ -24,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];
@@ -34,5 +34,5 @@ exports.cascade = function(operationSubFunction,options) {
results.push(result); results.push(result);
}); });
} }
}; }
}; };

View File

@@ -18,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
@@ -30,5 +30,5 @@ exports.filter = function(operationSubFunction,options) {
}); });
results.remove(resultsToRemove); results.remove(resultsToRemove);
} }
}; }
}; };

View File

@@ -7,6 +7,8 @@ Assign a value to a variable
\*/ \*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict"; "use strict";
/* /*

View File

@@ -20,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
@@ -28,12 +28,12 @@ exports.map = function(operationSubFunction,options) {
if(filtered.length && flatten) { if(filtered.length && flatten) {
$tw.utils.each(filtered,function(value) { $tw.utils.each(filtered,function(value) {
results.push(value); results.push(value);
}); })
} else { } else {
results.push(filtered[0]||""); results.push(filtered[0]||"");
} }
++index; ++index;
}); });
} }
}; }
}; };

View File

@@ -17,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,
@@ -31,5 +31,5 @@ exports.reduce = function(operationSubFunction,options) {
results.clear(); results.clear();
results.push(accumulator); results.push(accumulator);
} }
}; }
}; };

View File

@@ -24,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] || "");
}); });
@@ -36,12 +36,12 @@ exports.sort = function(operationSubFunction,options) {
// Sort the indexes // Sort the indexes
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive}); compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
indexes = indexes.sort(function(a,b) { indexes = indexes.sort(function(a,b) {
return compareFn(sortKeys[a],sortKeys[b]); return compareFn(sortKeys[a],sortKeys[b]);
}); });
// Add to results in correct order // Add to results in correct order
$tw.utils.each(indexes,function(index) { $tw.utils.each(indexes,function(index) {
results.push(inputTitles[index]); results.push(inputTitles[index]);
}); });
} }
}; }
}; };

View File

@@ -43,7 +43,7 @@ function parseFilterOperation(operators,filterString,p) {
var bracket = filterString.charAt(nextBracketPos); var bracket = filterString.charAt(nextBracketPos);
operator.operator = filterString.substring(p,nextBracketPos); operator.operator = filterString.substring(p,nextBracketPos);
// Any suffix? // Any suffix?
var colon = operator.operator.indexOf(":"); var colon = operator.operator.indexOf(':');
if(colon > -1) { if(colon > -1) {
// The raw suffix for older filters // The raw suffix for older filters
operator.suffix = operator.operator.substring(colon + 1); operator.suffix = operator.operator.substring(colon + 1);
@@ -67,7 +67,7 @@ function parseFilterOperation(operators,filterString,p) {
operator.operands = []; operator.operands = [];
var parseOperand = function(bracketType) { var parseOperand = function(bracketType) {
var operand = {}; var operand = {};
switch(bracketType) { switch (bracketType) {
case "{": // Curly brackets case "{": // Curly brackets
operand.indirect = true; operand.indirect = true;
nextBracketPos = filterString.indexOf("}",p); nextBracketPos = filterString.indexOf("}",p);
@@ -108,7 +108,7 @@ function parseFilterOperation(operators,filterString,p) {
} }
operator.operands.push(operand); operator.operands.push(operand);
p = nextBracketPos + 1; p = nextBracketPos + 1;
}; }
p = nextBracketPos + 1; p = nextBracketPos + 1;
parseOperand(bracket); parseOperand(bracket);
@@ -228,11 +228,16 @@ exports.getFilterRunPrefixes = function() {
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes); $tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
} }
return this.filterRunPrefixes; return this.filterRunPrefixes;
}; }
exports.filterTiddlers = function(filterString,widget,source) { exports.filterTiddlers = function(filterString,widget,source) {
var fn = this.compileFilter(filterString); var fn = this.compileFilter(filterString);
return fn.call(this,source,widget); try {
const fnResult = fn.call(this,source,widget);
return fnResult;
} catch(e) {
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
}
}; };
/* /*

View File

@@ -32,4 +32,4 @@ var modes = {
"gt": function(value) {return value > 0;}, "gt": function(value) {return value > 0;},
"lteq": function(value) {return value <= 0;}, "lteq": function(value) {return value <= 0;},
"lt": function(value) {return value < 0;} "lt": function(value) {return value < 0;}
}; }

View File

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

View File

@@ -15,8 +15,8 @@ Export our filter function
*/ */
exports.each = function(source,operator,options) { exports.each = function(source,operator,options) {
var results =[] , var results =[] ,
value,values = {}, value,values = {},
field = operator.operand || "title"; field = operator.operand || "title";
if(operator.suffix === "value" && field === "title") { if(operator.suffix === "value" && field === "title") {
source(function(tiddler,title) { source(function(tiddler,title) {
if(!$tw.utils.hop(values,title)) { if(!$tw.utils.hop(values,title)) {

View File

@@ -53,7 +53,7 @@ exports.field = function(source,operator,options) {
if(source.byField && operator.operand) { if(source.byField && operator.operand) {
indexedResults = source.byField(fieldname,operator.operand); indexedResults = source.byField(fieldname,operator.operand);
if(indexedResults) { if(indexedResults) {
return indexedResults; return indexedResults
} }
} }
source(function(tiddler,title) { source(function(tiddler,title) {

View File

@@ -24,7 +24,7 @@ exports.fields = function(source,operator,options) {
for(fieldName in tiddler.fields) { for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : ""; (operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : "";
} }
} else if(suffixes.indexOf("exclude") !== -1) { } else if (suffixes.indexOf("exclude") !== -1) {
for(fieldName in tiddler.fields) { for(fieldName in tiddler.fields) {
(operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName); (operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName);
} }

View File

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

@@ -12,7 +12,7 @@ Export our filter function
exports.timestamp = function(source,operand,options) { exports.timestamp = function(source,operand,options) {
var results = []; var results = [];
source(function(tiddler,title) { source(function(tiddler,title) {
if(title.match(/^-?\d+$/)) { if (title.match(/^-?\d+$/)) {
var value = new Date(Number(title)); var value = new Date(Number(title));
results.push($tw.utils.formatDateString(value,operand || "[UTC]YYYY0MM0DD0hh0mm0ss0XXX")); results.push($tw.utils.formatDateString(value,operand || "[UTC]YYYY0MM0DD0hh0mm0ss0XXX"));
} }

View File

@@ -13,7 +13,7 @@ returns the value at a given index of datatiddlers
Export our filter function Export our filter function
*/ */
exports.getindex = function(source,operator,options) { exports.getindex = function(source,operator,options) {
var data,results = []; var data,title,results = [];
if(operator.operand){ if(operator.operand){
source(function(tiddler,title) { source(function(tiddler,title) {
title = tiddler ? tiddler.fields.title : title; title = tiddler ? tiddler.fields.title : title;

View File

@@ -157,13 +157,13 @@ function convertDataItemValueToStrings(item) {
if(item === undefined) { if(item === undefined) {
return undefined; return undefined;
} else if(item === null) { } else if(item === null) {
return ["null"]; return ["null"]
} else if(typeof item === "object") { } else if(typeof item === "object") {
var results = [],i,t; var results = [],i,t;
if(Array.isArray(item)) { if(Array.isArray(item)) {
// Return all the items in arrays recursively // Return all the items in arrays recursively
for(i=0; i<item.length; i++) { for(i=0; i<item.length; i++) {
t = convertDataItemValueToStrings(item[i]); t = convertDataItemValueToStrings(item[i])
if(t !== undefined) { if(t !== undefined) {
results.push.apply(results,t); results.push.apply(results,t);
} }
@@ -231,7 +231,7 @@ function getItemAtIndex(item,index) {
return item[index]; return item[index];
} else if(Array.isArray(item)) { } else if(Array.isArray(item)) {
index = $tw.utils.parseInt(index); index = $tw.utils.parseInt(index);
if(index < 0) { index = index + item.length; }; if(index < 0) { index = index + item.length };
return item[index]; // Will be undefined if index was out-of-bounds return item[index]; // Will be undefined if index was out-of-bounds
} else { } else {
return undefined; return undefined;
@@ -289,7 +289,7 @@ function setDataItem(data,indexes,value) {
var lastIndex = indexes[indexes.length - 1]; var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current)) { if(Array.isArray(current)) {
lastIndex = $tw.utils.parseInt(lastIndex); lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length; }; if(lastIndex < 0) { lastIndex = lastIndex + current.length };
} }
// Only set indexes on objects and arrays // Only set indexes on objects and arrays
if(typeof current === "object") { if(typeof current === "object") {
@@ -316,7 +316,7 @@ function deleteDataItem(data,indexes) {
var lastIndex = indexes[indexes.length - 1]; var lastIndex = indexes[indexes.length - 1];
if(Array.isArray(current) && current !== null) { if(Array.isArray(current) && current !== null) {
lastIndex = $tw.utils.parseInt(lastIndex); lastIndex = $tw.utils.parseInt(lastIndex);
if(lastIndex < 0) { lastIndex = lastIndex + current.length; }; if(lastIndex < 0) { lastIndex = lastIndex + current.length };
// Check if index is valid before splicing // Check if index is valid before splicing
if(lastIndex >= 0 && lastIndex < current.length) { if(lastIndex >= 0 && lastIndex < current.length) {
current.splice(lastIndex,1); current.splice(lastIndex,1);

View File

@@ -25,7 +25,7 @@ exports.lookup = function(source,operator,options) {
indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false, indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false,
target; target;
if(operator.operands.length == 2) { if(operator.operands.length == 2) {
target = operator.operands[1]; target = operator.operands[1]
} else { } else {
target = indexSuffix ? "0": "text"; target = indexSuffix ? "0": "text";
} }

View File

@@ -17,35 +17,35 @@ Note that strings are converted to numbers automatically. Trailing non-digits ar
"use strict"; "use strict";
exports.negate = makeNumericBinaryOperator( exports.negate = makeNumericBinaryOperator(
function(a) {return -a;} function(a) {return -a}
); );
exports.abs = makeNumericBinaryOperator( exports.abs = makeNumericBinaryOperator(
function(a) {return Math.abs(a);} function(a) {return Math.abs(a)}
); );
exports.ceil = makeNumericBinaryOperator( exports.ceil = makeNumericBinaryOperator(
function(a) {return Math.ceil(a);} function(a) {return Math.ceil(a)}
); );
exports.floor = makeNumericBinaryOperator( exports.floor = makeNumericBinaryOperator(
function(a) {return Math.floor(a);} function(a) {return Math.floor(a)}
); );
exports.round = makeNumericBinaryOperator( exports.round = makeNumericBinaryOperator(
function(a) {return Math.round(a);} function(a) {return Math.round(a)}
); );
exports.trunc = makeNumericBinaryOperator( exports.trunc = makeNumericBinaryOperator(
function(a) {return Math.trunc(a);} function(a) {return Math.trunc(a)}
); );
exports.untrunc = makeNumericBinaryOperator( exports.untrunc = makeNumericBinaryOperator(
function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a);} function(a) {return Math.ceil(Math.abs(a)) * Math.sign(a)}
); );
exports.sign = makeNumericBinaryOperator( exports.sign = makeNumericBinaryOperator(
function(a) {return Math.sign(a);} function(a) {return Math.sign(a)}
); );
exports.add = makeNumericBinaryOperator( exports.add = makeNumericBinaryOperator(
@@ -103,29 +103,29 @@ exports.log = makeNumericBinaryOperator(
); );
exports.sum = makeNumericReducingOperator( exports.sum = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;}, function(accumulator,value) {return accumulator + value},
0 // Initial value 0 // Initial value
); );
exports.product = makeNumericReducingOperator( exports.product = makeNumericReducingOperator(
function(accumulator,value) {return accumulator * value;}, function(accumulator,value) {return accumulator * value},
1 // Initial value 1 // Initial value
); );
exports.maxall = makeNumericReducingOperator( exports.maxall = makeNumericReducingOperator(
function(accumulator,value) {return Math.max(accumulator,value);}, function(accumulator,value) {return Math.max(accumulator,value)},
-Infinity // Initial value -Infinity // Initial value
); );
exports.minall = makeNumericReducingOperator( exports.minall = makeNumericReducingOperator(
function(accumulator,value) {return Math.min(accumulator,value);}, function(accumulator,value) {return Math.min(accumulator,value)},
Infinity // Initial value Infinity // Initial value
); );
exports.median = makeNumericArrayOperator( exports.median = makeNumericArrayOperator(
function(values) { function(values) {
var len = values.length, median; var len = values.length, median;
values.sort(function(a,b) {return a-b;}); values.sort(function(a,b) {return a-b});
if(len % 2) { if(len % 2) {
// Odd, return the middle number // Odd, return the middle number
median = values[(len - 1) / 2]; median = values[(len - 1) / 2];
@@ -138,7 +138,7 @@ exports.median = makeNumericArrayOperator(
); );
exports.average = makeNumericReducingOperator( exports.average = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;}, function(accumulator,value) {return accumulator + value},
0, // Initial value 0, // Initial value
function(finalValue,numberOfValues) { function(finalValue,numberOfValues) {
return finalValue/numberOfValues; return finalValue/numberOfValues;
@@ -146,7 +146,7 @@ exports.average = makeNumericReducingOperator(
); );
exports.variance = makeNumericReducingOperator( exports.variance = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;}, function(accumulator,value) {return accumulator + value},
0, 0,
function(finalValue,numberOfValues,originalValues) { function(finalValue,numberOfValues,originalValues) {
return getVarianceFromArray(originalValues,finalValue/numberOfValues); return getVarianceFromArray(originalValues,finalValue/numberOfValues);
@@ -154,7 +154,7 @@ exports.variance = makeNumericReducingOperator(
); );
exports["standard-deviation"] = makeNumericReducingOperator( exports["standard-deviation"] = makeNumericReducingOperator(
function(accumulator,value) {return accumulator + value;}, function(accumulator,value) {return accumulator + value},
0, 0,
function(finalValue,numberOfValues,originalValues) { function(finalValue,numberOfValues,originalValues) {
var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues); var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues);
@@ -164,31 +164,31 @@ exports["standard-deviation"] = makeNumericReducingOperator(
//trigonometry //trigonometry
exports.cos = makeNumericBinaryOperator( exports.cos = makeNumericBinaryOperator(
function(a) {return Math.cos(a);} function(a) {return Math.cos(a)}
); );
exports.sin = makeNumericBinaryOperator( exports.sin = makeNumericBinaryOperator(
function(a) {return Math.sin(a);} function(a) {return Math.sin(a)}
); );
exports.tan = makeNumericBinaryOperator( exports.tan = makeNumericBinaryOperator(
function(a) {return Math.tan(a);} function(a) {return Math.tan(a)}
); );
exports.acos = makeNumericBinaryOperator( exports.acos = makeNumericBinaryOperator(
function(a) {return Math.acos(a);} function(a) {return Math.acos(a)}
); );
exports.asin = makeNumericBinaryOperator( exports.asin = makeNumericBinaryOperator(
function(a) {return Math.asin(a);} function(a) {return Math.asin(a)}
); );
exports.atan = makeNumericBinaryOperator( exports.atan = makeNumericBinaryOperator(
function(a) {return Math.atan(a);} function(a) {return Math.atan(a)}
); );
exports.atan2 = makeNumericBinaryOperator( exports.atan2 = makeNumericBinaryOperator(
function(a,b) {return Math.atan2(a,b);} function(a,b) {return Math.atan2(a,b)}
); );
//Calculate the variance of a population of numbers in an array given its mean //Calculate the variance of a population of numbers in an array given its mean
@@ -222,8 +222,8 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
return []; return [];
} }
var value = result.reduce(function(accumulator,currentValue) { var value = result.reduce(function(accumulator,currentValue) {
return fnCalc(accumulator,currentValue); return fnCalc(accumulator,currentValue);
},initialValue); },initialValue);
if(fnFinal) { if(fnFinal) {
value = fnFinal(value,result.length,result); value = fnFinal(value,result.length,result);
} }

View File

@@ -21,7 +21,7 @@ exports.range = function(source,operator,options) {
} }
// Process the parts // Process the parts
var beg, end, inc, i, fixed = 0; var beg, end, inc, i, fixed = 0;
for(i=0; i<parts.length; i++) { for (i=0; i<parts.length; i++) {
// Validate real number // Validate real number
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) { if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
return ["range: bad number \"" + parts[i] + "\""]; return ["range: bad number \"" + parts[i] + "\""];
@@ -36,10 +36,10 @@ exports.range = function(source,operator,options) {
switch(parts.length) { switch(parts.length) {
case 1: case 1:
end = parts[0]; end = parts[0];
if(end >= 1) { if (end >= 1) {
beg = 1; beg = 1;
} }
else if(end <= -1) { else if (end <= -1) {
beg = -1; beg = -1;
} }
else { else {
@@ -72,7 +72,7 @@ exports.range = function(source,operator,options) {
end += direction * 0.5 * Math.pow(0.1,fixed); end += direction * 0.5 * Math.pow(0.1,fixed);
var safety = 10010; var safety = 10010;
// Enumerate the range // Enumerate the range
if(end<beg) { if (end<beg) {
for(i=beg; i>end; i+=inc) { for(i=beg; i>end; i+=inc) {
results.push(i.toFixed(fixed)); results.push(i.toFixed(fixed));
if(--safety<0) { if(--safety<0) {

View File

@@ -15,7 +15,7 @@ Export our filter function
exports.removesuffix = function(source,operator,options) { exports.removesuffix = function(source,operator,options) {
var results = [], var results = [],
suffixes = (operator.suffixes || [])[0] || []; suffixes = (operator.suffixes || [])[0] || [];
if(!operator.operand) { if (!operator.operand) {
source(function(tiddler,title) { source(function(tiddler,title) {
results.push(title); results.push(title);
}); });

View File

@@ -14,31 +14,31 @@ Export our filter function
*/ */
exports.sort = function(source,operator,options) { exports.sort = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
return results; return results;
}; };
exports.nsort = function(source,operator,options) { exports.nsort = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
return results; return results;
}; };
exports.sortan = function(source, operator, options) { exports.sortan = function(source, operator, options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]); options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
return results; return results;
}; };
exports.sortcs = function(source,operator,options) { exports.sortcs = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
return results; return results;
}; };
exports.nsortcs = function(source,operator,options) { exports.nsortcs = function(source,operator,options) {
var results = prepare_results(source); var results = prepare_results(source);
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]); options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
return results; return results;
}; };

View File

@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
operand = (operator.operand || ""), operand = (operator.operand || ""),
fnCalc; fnCalc;
if(suffix === "prefix") { if(suffix === "prefix") {
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}; fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
} else if(suffix === "suffix") { } else if(suffix === "suffix") {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}; fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
} else { } else {
if(operand === "") { if(operand === "") {
fnCalc = function(a) {return [$tw.utils.trim(a)];}; fnCalc = function(a) {return [$tw.utils.trim(a)];}
} else { } else {
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}; fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
} }
} }
source(function(tiddler,title) { source(function(tiddler,title) {
@@ -71,53 +71,107 @@ exports.join = makeStringReducingOperator(
},null },null
); );
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js"); var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
exports.levenshtein = makeStringBinaryOperator( exports.levenshtein = makeStringBinaryOperator(
function(a,b) { function(a,b) {
const diffs = dmp.diffMain(a,b); var dmpObject = new dmp.diff_match_patch(),
return [dmp.diffLevenshtein(diffs).toString()]; diffs = dmpObject.diff_main(a,b);
return [dmpObject.diff_levenshtein(diffs) + ""];
} }
); );
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs // these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
function diffLineWordMode(text1,text2,mode) { function diffLineWordMode(text1,text2,mode) {
var a = $tw.utils.diffPartsToChars(text1,text2,mode); var dmpObject = new dmp.diff_match_patch();
var a = diffPartsToChars(text1,text2,mode);
var lineText1 = a.chars1; var lineText1 = a.chars1;
var lineText2 = a.chars2; var lineText2 = a.chars2;
var lineArray = a.lineArray; var lineArray = a.lineArray;
var diffs = dmp.diffMain(lineText1,lineText2,false); var diffs = dmpObject.diff_main(lineText1,lineText2,false);
dmp.diffCharsToLines(diffs,lineArray); dmpObject.diff_charsToLines_(diffs,lineArray);
return diffs; return diffs;
} }
function diffPartsToChars(text1,text2,mode) {
var lineArray = [];
var lineHash = {};
lineArray[0] = '';
function diff_linesToPartsMunge_(text,mode) {
var chars = '';
var lineStart = 0;
var lineEnd = -1;
var lineArrayLength = lineArray.length,
regexpResult;
var searchRegexp = /\W+/g;
while(lineEnd < text.length - 1) {
if(mode === "words") {
regexpResult = searchRegexp.exec(text);
lineEnd = searchRegexp.lastIndex;
if(regexpResult === null) {
lineEnd = text.length;
}
lineEnd = --lineEnd;
} else {
lineEnd = text.indexOf('\n', lineStart);
if(lineEnd == -1) {
lineEnd = text.length - 1;
}
}
var line = text.substring(lineStart, lineEnd + 1);
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
chars += String.fromCharCode(lineHash[line]);
} else {
if(lineArrayLength == maxLines) {
line = text.substring(lineStart);
lineEnd = text.length;
}
chars += String.fromCharCode(lineArrayLength);
lineHash[line] = lineArrayLength;
lineArray[lineArrayLength++] = line;
}
lineStart = lineEnd + 1;
}
return chars;
}
var maxLines = 40000;
var chars1 = diff_linesToPartsMunge_(text1,mode);
maxLines = 65535;
var chars2 = diff_linesToPartsMunge_(text2,mode);
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
};
exports.makepatches = function(source,operator,options) { exports.makepatches = function(source,operator,options) {
var suffix = operator.suffix || "", var dmpObject = new dmp.diff_match_patch(),
suffix = operator.suffix || "",
result = []; result = [];
source(function(tiddler,title) { source(function(tiddler,title) {
let diffs, patches; var diffs, patches;
if(suffix === "lines" || suffix === "words") { if(suffix === "lines" || suffix === "words") {
diffs = diffLineWordMode(title,operator.operand,suffix); diffs = diffLineWordMode(title,operator.operand,suffix);
patches = dmp.patchMake(title,diffs); patches = dmpObject.patch_make(title,diffs);
} else { } else {
patches = dmp.patchMake(title,operator.operand); patches = dmpObject.patch_make(title,operator.operand);
} }
Array.prototype.push.apply(result,[dmp.patchToText(patches)]); Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
}); });
return result; return result;
}; };
exports.applypatches = makeStringBinaryOperator( exports.applypatches = makeStringBinaryOperator(
function(a,b) { function(a,b) {
let patches; var dmpObject = new dmp.diff_match_patch(),
patches;
try { try {
patches = dmp.patchFromText(b); patches = dmpObject.patch_fromText(b);
} catch(e) { } catch(e) {
} }
if(patches) { if(patches) {
return [dmp.patchApply(patches,a)[0]]; return [dmpObject.patch_apply(patches,a)[0]];
} else { } else {
return [a]; return [a];
} }
@@ -225,7 +279,7 @@ exports.pad = function(source,operator,options) {
} }
}); });
return results; return results;
}; }
exports.charcode = function(source,operator,options) { exports.charcode = function(source,operator,options) {
var chars = []; var chars = [];

View File

@@ -15,7 +15,7 @@ Export our filter function
exports.suffix = function(source,operator,options) { exports.suffix = function(source,operator,options) {
var results = [], var results = [],
suffixes = (operator.suffixes || [])[0] || []; suffixes = (operator.suffixes || [])[0] || [];
if(!operator.operand) { if (!operator.operand) {
source(function(tiddler,title) { source(function(tiddler,title) {
results.push(title); results.push(title);
}); });

View File

@@ -24,4 +24,4 @@ exports.variables = function(source,operator,options) {
} }
} }
return names.sort(); return names.sort();
}; };

View File

@@ -7,224 +7,224 @@ Extended filter operators to manipulate the current list.
\*/ \*/
"use strict"; "use strict";
/* /*
Fetch titles from the current list Fetch titles from the current list
*/ */
var prepare_results = function (source) { var prepare_results = function (source) {
var results = []; var results = [];
source(function (tiddler, title) { source(function (tiddler, title) {
results.push(title); results.push(title);
}); });
return results; return results;
}; };
/* /*
Moves a number of items from the tail of the current list before the item named in the operand Moves a number of items from the tail of the current list before the item named in the operand
*/ */
exports.putbefore = function (source, operator) { exports.putbefore = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand), index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1); count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ? return (index === -1) ?
results.slice(0, -1) : results.slice(0, -1) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count)); results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
}; };
/* /*
Moves a number of items from the tail of the current list after the item named in the operand Moves a number of items from the tail of the current list after the item named in the operand
*/ */
exports.putafter = function (source, operator) { exports.putafter = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand), index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1); count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ? return (index === -1) ?
results.slice(0, -1) : results.slice(0, -1) :
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count)); results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
}; };
/* /*
Replaces the item named in the operand with a number of items from the tail of the current list Replaces the item named in the operand with a number of items from the tail of the current list
*/ */
exports.replace = function (source, operator) { exports.replace = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand), index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1); count = $tw.utils.getInt(operator.suffix,1);
return (index === -1) ? return (index === -1) ?
results.slice(0, -count) : results.slice(0, -count) :
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count)); results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
}; };
/* /*
Moves a number of items from the tail of the current list to the head of the list Moves a number of items from the tail of the current list to the head of the list
*/ */
exports.putfirst = function (source, operator) { exports.putfirst = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1); count = $tw.utils.getInt(operator.suffix,1);
return results.slice(-count).concat(results.slice(0, -count)); return results.slice(-count).concat(results.slice(0, -count));
}; };
/* /*
Moves a number of items from the head of the current list to the tail of the list Moves a number of items from the head of the current list to the tail of the list
*/ */
exports.putlast = function (source, operator) { exports.putlast = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,1); count = $tw.utils.getInt(operator.suffix,1);
return results.slice(count).concat(results.slice(0, count)); return results.slice(count).concat(results.slice(0, count));
}; };
/* /*
Moves the item named in the operand a number of places forward or backward in the list Moves the item named in the operand a number of places forward or backward in the list
*/ */
exports.move = function (source, operator) { exports.move = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand), index = results.indexOf(operator.operand),
count = $tw.utils.getInt(operator.suffix,1), count = $tw.utils.getInt(operator.suffix,1),
marker = results.splice(index, 1), marker = results.splice(index, 1),
offset = (index + count) > 0 ? index + count : 0; offset = (index + count) > 0 ? index + count : 0;
return results.slice(0, offset).concat(marker).concat(results.slice(offset)); return results.slice(0, offset).concat(marker).concat(results.slice(offset));
}; };
/* /*
Returns the items from the current list that are after the item named in the operand Returns the items from the current list that are after the item named in the operand
*/ */
exports.allafter = function (source, operator) { exports.allafter = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand); index = results.indexOf(operator.operand);
return (index === -1) ? [] : return (index === -1) ? [] :
(operator.suffix) ? results.slice(index) : (operator.suffix) ? results.slice(index) :
results.slice(index + 1); results.slice(index + 1);
}; };
/* /*
Returns the items from the current list that are before the item named in the operand Returns the items from the current list that are before the item named in the operand
*/ */
exports.allbefore = function (source, operator) { exports.allbefore = function (source, operator) {
var results = prepare_results(source), var results = prepare_results(source),
index = results.indexOf(operator.operand); index = results.indexOf(operator.operand);
return (index === -1) ? [] : return (index === -1) ? [] :
(operator.suffix) ? results.slice(0, index + 1) : (operator.suffix) ? results.slice(0, index + 1) :
results.slice(0, index); results.slice(0, index);
}; };
/* /*
Appends the items listed in the operand array to the tail of the current list Appends the items listed in the operand array to the tail of the current list
*/ */
exports.append = function (source, operator) { exports.append = function (source, operator) {
var append = $tw.utils.parseStringArray(operator.operand, "true"), var append = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source), results = prepare_results(source),
count = parseInt(operator.suffix) || append.length; count = parseInt(operator.suffix) || append.length;
return (append.length === 0) ? results : return (append.length === 0) ? results :
(operator.prefix) ? results.concat(append.slice(-count)) : (operator.prefix) ? results.concat(append.slice(-count)) :
results.concat(append.slice(0, count)); results.concat(append.slice(0, count));
}; };
/* /*
Prepends the items listed in the operand array to the head of the current list Prepends the items listed in the operand array to the head of the current list
*/ */
exports.prepend = function (source, operator) { exports.prepend = function (source, operator) {
var prepend = $tw.utils.parseStringArray(operator.operand, "true"), var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source), results = prepare_results(source),
count = $tw.utils.getInt(operator.suffix,prepend.length); count = $tw.utils.getInt(operator.suffix,prepend.length);
return (prepend.length === 0) ? results : return (prepend.length === 0) ? results :
(operator.prefix) ? prepend.slice(-count).concat(results) : (operator.prefix) ? prepend.slice(-count).concat(results) :
prepend.slice(0, count).concat(results); prepend.slice(0, count).concat(results);
}; };
/* /*
Returns all items from the current list except the items listed in the operand array Returns all items from the current list except the items listed in the operand array
*/ */
exports.remove = function (source, operator) { exports.remove = function (source, operator) {
var array = $tw.utils.parseStringArray(operator.operand, "true"), var array = $tw.utils.parseStringArray(operator.operand, "true"),
results = prepare_results(source), results = prepare_results(source),
count = parseInt(operator.suffix) || array.length, count = parseInt(operator.suffix) || array.length,
p, p,
len, len,
index; index;
len = array.length - 1; len = array.length - 1;
for(p = 0; p < count; ++p) { for (p = 0; p < count; ++p) {
if(operator.prefix) { if (operator.prefix) {
index = results.indexOf(array[len - p]); index = results.indexOf(array[len - p]);
} else { } else {
index = results.indexOf(array[p]); index = results.indexOf(array[p]);
}
if (index !== -1) {
results.splice(index, 1);
}
} }
if(index !== -1) { return results;
results.splice(index, 1); };
}
}
return results;
};
/* /*
Returns all items from the current list sorted in the order of the items in the operand array Returns all items from the current list sorted in the order of the items in the operand array
*/ */
exports.sortby = function (source, operator) { exports.sortby = function (source, operator) {
var results = prepare_results(source); var results = prepare_results(source);
if(!results || results.length < 2) { if (!results || results.length < 2) {
return results;
}
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
results.sort(function (a, b) {
return lookup.indexOf(a) - lookup.indexOf(b);
});
return results; return results;
} };
var lookup = $tw.utils.parseStringArray(operator.operand, "true");
results.sort(function (a, b) {
return lookup.indexOf(a) - lookup.indexOf(b);
});
return results;
};
/* /*
Removes all duplicate items from the current list Removes all duplicate items from the current list
*/ */
exports.unique = function (source, operator) { exports.unique = function (source, operator) {
var results = prepare_results(source); var results = prepare_results(source);
var set = results.reduce(function (a, b) { var set = results.reduce(function (a, b) {
if(a.indexOf(b) < 0) { if (a.indexOf(b) < 0) {
a.push(b); a.push(b);
} }
return a; return a;
}, []); }, []);
return set; return set;
}; };
var cycleValueInArray = function(results,operands,stepSize) { var cycleValueInArray = function(results,operands,stepSize) {
var resultsIndex, var resultsIndex,
step = stepSize || 1, step = stepSize || 1,
i = 0, i = 0,
opLength = operands.length, opLength = operands.length,
nextOperandIndex; nextOperandIndex;
for(i; i < opLength; i++) { for(i; i < opLength; i++) {
resultsIndex = results.indexOf(operands[i]); resultsIndex = results.indexOf(operands[i]);
if(resultsIndex !== -1) {
break;
}
}
if(resultsIndex !== -1) { if(resultsIndex !== -1) {
break; i = i + step;
} nextOperandIndex = (i < opLength ? i : i % opLength);
} if(operands.length > 1) {
if(resultsIndex !== -1) { results.splice(resultsIndex,1,operands[nextOperandIndex]);
i = i + step; } else {
nextOperandIndex = (i < opLength ? i : i % opLength); results.splice(resultsIndex,1);
if(operands.length > 1) { }
results.splice(resultsIndex,1,operands[nextOperandIndex]);
} else { } else {
results.splice(resultsIndex,1); results.push(operands[0]);
} }
} else { return results;
results.push(operands[0]);
} }
return results;
};
/* /*
Toggles an item in the current list. Toggles an item in the current list.
*/ */
exports.toggle = function(source,operator) { exports.toggle = function(source,operator) {
return cycleValueInArray(prepare_results(source),operator.operands); return cycleValueInArray(prepare_results(source),operator.operands);
}; }
exports.cycle = function(source,operator) { exports.cycle = function(source,operator) {
var results = prepare_results(source), var results = prepare_results(source),
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]), operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
step = $tw.utils.getInt(operator.operands[1]||"",1); step = $tw.utils.getInt(operator.operands[1]||"",1);
if(step < 0) { if(step < 0) {
operands.reverse(); operands.reverse();
step = Math.abs(step); step = Math.abs(step);
}
return cycleValueInArray(results,operands,step);
} }
return cycleValueInArray(results,operands,step);
};

View File

@@ -46,7 +46,7 @@ function BackSubIndexer(indexer,extractor) {
BackSubIndexer.prototype.init = function() { BackSubIndexer.prototype.init = function() {
// lazy init until first lookup // lazy init until first lookup
this.index = null; this.index = null;
}; }
BackSubIndexer.prototype._init = function() { BackSubIndexer.prototype._init = function() {
this.index = Object.create(null); this.index = Object.create(null);
@@ -60,11 +60,11 @@ BackSubIndexer.prototype._init = function() {
self.index[target][sourceTitle] = true; self.index[target][sourceTitle] = true;
}); });
}); });
}; }
BackSubIndexer.prototype.rebuild = function() { BackSubIndexer.prototype.rebuild = function() {
this.index = null; this.index = null;
}; }
/* /*
* Get things that is being referenced in the text, e.g. tiddler names in the link syntax. * Get things that is being referenced in the text, e.g. tiddler names in the link syntax.
@@ -78,7 +78,7 @@ BackSubIndexer.prototype._getTarget = function(tiddler) {
return this.wiki[this.extractor](parser.tree, tiddler.fields.title); return this.wiki[this.extractor](parser.tree, tiddler.fields.title);
} }
return []; return [];
}; }
BackSubIndexer.prototype.update = function(updateDescriptor) { BackSubIndexer.prototype.update = function(updateDescriptor) {
// lazy init/update until first lookup // lazy init/update until first lookup
@@ -86,8 +86,8 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
return; return;
} }
var newTargets = [], var newTargets = [],
oldTargets = [], oldTargets = [],
self = this; self = this;
if(updateDescriptor.old.exists) { if(updateDescriptor.old.exists) {
oldTargets = this._getTarget(updateDescriptor.old.tiddler); oldTargets = this._getTarget(updateDescriptor.old.tiddler);
} }
@@ -106,7 +106,7 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
} }
self.index[target][updateDescriptor.new.tiddler.fields.title] = true; self.index[target][updateDescriptor.new.tiddler.fields.title] = true;
}); });
}; }
BackSubIndexer.prototype.lookup = function(title) { BackSubIndexer.prototype.lookup = function(title) {
if(!this.index) { if(!this.index) {
@@ -117,6 +117,6 @@ BackSubIndexer.prototype.lookup = function(title) {
} else { } else {
return []; return [];
} }
}; }
exports.BackIndexer = BackIndexer; exports.BackIndexer = BackIndexer;

View File

@@ -19,7 +19,7 @@ FieldIndexer.prototype.init = function() {
this.index = null; this.index = null;
this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH; this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH;
this.addIndexMethods(); this.addIndexMethods();
}; }
// Provided for testing // Provided for testing
FieldIndexer.prototype.setMaxIndexedValueLength = function(length) { FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
@@ -33,14 +33,14 @@ FieldIndexer.prototype.addIndexMethods = function() {
this.wiki.each.byField = function(name,value) { this.wiki.each.byField = function(name,value) {
var lookup = self.lookup(name,value); var lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) { return lookup && lookup.filter(function(title) {
return self.wiki.tiddlerExists(title); return self.wiki.tiddlerExists(title)
}); });
}; };
// get shadow tiddlers, including shadow tiddlers that is overwritten // get shadow tiddlers, including shadow tiddlers that is overwritten
this.wiki.eachShadow.byField = function(name,value) { this.wiki.eachShadow.byField = function(name,value) {
var lookup = self.lookup(name,value); var lookup = self.lookup(name,value);
return lookup && lookup.filter(function(title) { return lookup && lookup.filter(function(title) {
return self.wiki.isShadowTiddler(title); return self.wiki.isShadowTiddler(title)
}); });
}; };
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) { this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {

View File

@@ -14,12 +14,12 @@ exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
this.updateCallback = updateCallback; this.updateCallback = updateCallback;
this.resizeHandlers = new Map(); this.resizeHandlers = new Map();
this.dimensionsInfo = [ this.dimensionsInfo = [
["outer/width", (win) => win.outerWidth], ["outer/width", win => win.outerWidth],
["outer/height", (win) => win.outerHeight], ["outer/height", win => win.outerHeight],
["inner/width", (win) => win.innerWidth], ["inner/width", win => win.innerWidth],
["inner/height", (win) => win.innerHeight], ["inner/height", win => win.innerHeight],
["client/width", (win) => win.document.documentElement.clientWidth], ["client/width", win => win.document.documentElement.clientWidth],
["client/height", (win) => win.document.documentElement.clientHeight] ["client/height", win => win.document.documentElement.clientHeight]
]; ];
} }

View File

@@ -1,67 +0,0 @@
/*\
title: $:/core/modules/info/mediaquerytracker.js
type: application/javascript
module-type: info
Initialise $:/info/ tiddlers derived from media queries via
\*/
"use strict";
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
if($tw.browser) {
// Functions to start and stop tracking a particular media query tracker tiddler
function track(title) {
var result = {},
tiddler = $tw.wiki.getTiddler(title);
if(tiddler) {
var mediaQuery = tiddler.fields["media-query"],
infoTiddler = tiddler.fields["info-tiddler"],
infoTiddlerAlt = tiddler.fields["info-tiddler-alt"];
if(mediaQuery && infoTiddler) {
// Evaluate and track the media query
result.mqList = window.matchMedia(mediaQuery);
function getResultTiddlers() {
var value = result.mqList.matches ? "yes" : "no",
tiddlers = [];
tiddlers.push({title: infoTiddler, text: value});
if(infoTiddlerAlt) {
tiddlers.push({title: infoTiddlerAlt, text: value});
}
return tiddlers;
};
updateInfoTiddlersCallback(getResultTiddlers());
result.handler = function(event) {
updateInfoTiddlersCallback(getResultTiddlers());
};
result.mqList.addEventListener("change",result.handler);
}
}
return result;
}
function untrack(enterValue) {
if(enterValue.mqList && enterValue.handler) {
enterValue.mqList.removeEventListener("change",enterValue.handler);
}
}
// Track media query tracker tiddlers
function fnEnter(title) {
return track(title);
}
function fnLeave(title,enterValue) {
untrack(enterValue);
}
function fnChange(title,enterValue) {
untrack(enterValue);
return track(title);
}
$tw.filterTracker.track({
filterString: "[all[tiddlers+shadows]tag[$:/tags/MediaQueryTracker]!is[draft]]",
fnEnter: fnEnter,
fnLeave: fnLeave,
fnChange: fnChange
});
}
return [];
};

View File

@@ -33,6 +33,13 @@ exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
// Screen size // Screen size
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()}); infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.toString()});
infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()}); infoTiddlerFields.push({title: "$:/info/browser/screen/height", text: window.screen.height.toString()});
// Dark mode through event listener on MediaQueryList
var mqList = window.matchMedia("(prefers-color-scheme: dark)"),
getDarkModeTiddler = function() {return {title: "$:/info/darkmode", text: mqList.matches ? "yes" : "no"};};
infoTiddlerFields.push(getDarkModeTiddler());
mqList.addListener(function(event) {
updateInfoTiddlersCallback([getDarkModeTiddler()]);
});
// Language // Language
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""}); infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
} }

View File

@@ -140,7 +140,7 @@ function KeyboardManager(options) {
this.shortcutParsedList = []; // Stores the parsed key descriptors this.shortcutParsedList = []; // Stores the parsed key descriptors
this.shortcutPriorityList = []; // Stores the parsed shortcut priority this.shortcutPriorityList = []; // Stores the parsed shortcut priority
this.lookupNames = ["shortcuts"]; this.lookupNames = ["shortcuts"];
this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac"); this.lookupNames.push($tw.platform.isMac ? "shortcuts-mac" : "shortcuts-not-mac")
this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows"); this.lookupNames.push($tw.platform.isWindows ? "shortcuts-windows" : "shortcuts-not-windows");
this.lookupNames.push($tw.platform.isLinux ? "shortcuts-linux" : "shortcuts-not-linux"); this.lookupNames.push($tw.platform.isLinux ? "shortcuts-linux" : "shortcuts-not-linux");
this.updateShortcutLists(this.getShortcutTiddlerList()); this.updateShortcutLists(this.getShortcutTiddlerList());
@@ -161,7 +161,7 @@ KeyboardManager.prototype.getModifierKeys = function() {
91, // Meta (left) 91, // Meta (left)
93, // Meta (right) 93, // Meta (right)
224 // Meta (Firefox) 224 // Meta (Firefox)
]; ]
}; };
/* /*
@@ -187,7 +187,8 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
metaKey: false metaKey: false
}; };
for(var t=0; t<components.length; t++) { for(var t=0; t<components.length; t++) {
var s = components[t].toLowerCase(); var s = components[t].toLowerCase(),
c = s.charCodeAt(0);
// Look for modifier keys // Look for modifier keys
if(s === "ctrl") { if(s === "ctrl") {
info.ctrlKey = true; info.ctrlKey = true;
@@ -265,7 +266,7 @@ KeyboardManager.prototype.getPrintableShortcuts = function(keyInfoArray) {
} }
}); });
return result; return result;
}; }
KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) { KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
return keyInfo && return keyInfo &&
@@ -292,15 +293,15 @@ KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) { KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" : return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" : event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "shift" :
event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" : event.ctrlKey && event.shiftKey && !event.altKey && !event.metaKey ? "ctrl-shift" :
event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" : event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt" :
event.altKey && event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt-shift" : event.altKey && event.shiftKey && !event.ctrlKey && !event.metaKey ? "alt-shift" :
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" : event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
event.altKey && event.shiftKey && event.ctrlKey && !event.metaKey ? "ctrl-alt-shift" : event.altKey && event.shiftKey && event.ctrlKey && !event.metaKey ? "ctrl-alt-shift" :
event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" : event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey ? "meta" :
event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" : event.metaKey && event.ctrlKey && !event.shiftKey && !event.altKey ? "meta-ctrl" :
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" : event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal"; event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
}; };
KeyboardManager.prototype.getShortcutTiddlerList = function() { KeyboardManager.prototype.getShortcutTiddlerList = function() {
@@ -370,8 +371,8 @@ KeyboardManager.prototype.handleShortcutChanges = function(changedTiddlers) {
var newList = this.getShortcutTiddlerList(); var newList = this.getShortcutTiddlerList();
var hasChanged = $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers) ? true : var hasChanged = $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers) ? true :
($tw.utils.hopArray(changedTiddlers,newList) ? true : ($tw.utils.hopArray(changedTiddlers,newList) ? true :
(this.detectNewShortcuts(changedTiddlers)) (this.detectNewShortcuts(changedTiddlers))
); );
// Re-cache shortcuts if something changed // Re-cache shortcuts if something changed
if(hasChanged) { if(hasChanged) {
this.updateShortcutLists(newList); this.updateShortcutLists(newList);

View File

@@ -24,7 +24,8 @@ exports.params = [
Run the macro Run the macro
*/ */
exports.run = function(filter,format) { exports.run = function(filter,format) {
var tiddlers = this.wiki.filterTiddlers(filter), var self = this,
tiddlers = this.wiki.filterTiddlers(filter),
tiddler, tiddler,
fields = [], fields = [],
t,f; t,f;
@@ -45,24 +46,24 @@ exports.run = function(filter,format) {
var p = fields.indexOf(value); var p = fields.indexOf(value);
if(p !== -1) { if(p !== -1) {
fields.splice(p,1); fields.splice(p,1);
fields.unshift(value); fields.unshift(value)
} }
}); });
// Output the column headings // Output the column headings
var output = [], row = []; var output = [], row = [];
fields.forEach(function(value) { fields.forEach(function(value) {
row.push(quoteAndEscape(value)); row.push(quoteAndEscape(value))
}); });
output.push(row.join(",")); output.push(row.join(","));
// Output each tiddler // Output each tiddler
for(var t=0;t<tiddlers.length; t++) { for(var t=0;t<tiddlers.length; t++) {
row = []; row = [];
tiddler = this.wiki.getTiddler(tiddlers[t]); tiddler = this.wiki.getTiddler(tiddlers[t]);
if(tiddler) { if(tiddler) {
for(f=0; f<fields.length; f++) { for(f=0; f<fields.length; f++) {
row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : "")); row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : ""));
} }
} }
output.push(row.join(",")); output.push(row.join(","));
} }
return output.join("\n"); return output.join("\n");

View File

@@ -31,8 +31,8 @@ exports.run = function(shortcuts,prefix,separator,suffix) {
})); }));
if(shortcutArray.length > 0) { if(shortcutArray.length > 0) {
shortcutArray.sort(function(a,b) { shortcutArray.sort(function(a,b) {
return a.toLowerCase().localeCompare(b.toLowerCase()); return a.toLowerCase().localeCompare(b.toLowerCase());
}); })
return prefix + shortcutArray.join(separator) + suffix; return prefix + shortcutArray.join(separator) + suffix;
} else { } else {
return ""; return "";

View File

@@ -7,17 +7,19 @@ The audio parser parses an audio tiddler into an embeddable HTML element
\*/ \*/
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict"; "use strict";
var AudioParser = function(type,text,options) { var AudioParser = function(type,text,options) {
var element = { var element = {
type: "element", type: "element",
tag: "$audio", // Using $audio to enable widget interception tag: "$audio", // Using $audio to enable widget interception
attributes: { attributes: {
controls: {type: "string", value: "controls"}, controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"} style: {type: "string", value: "width: 100%; object-fit: contain"}
} }
}; };
// Pass through source information // Pass through source information
if(options._canonical_uri) { if(options._canonical_uri) {

View File

@@ -59,7 +59,7 @@ var BinaryParser = function(type,text,options) {
class: {type: "string", value: "tc-binary-warning"} class: {type: "string", value: "tc-binary-warning"}
}, },
children: [warn, link] children: [warn, link]
}; }
this.tree = [element]; this.tree = [element];
this.source = text; this.source = text;
this.type = type; this.type = type;

View File

@@ -45,7 +45,7 @@ var CsvParser = function(type,text,options) {
row.children.push({ row.children.push({
"type": "element", "tag": tag, "children": [{ "type": "element", "tag": tag, "children": [{
"type": "text", "type": "text",
"text": columns[column] || "" "text": columns[column] || ''
}] }]
}); });
} }

View File

@@ -11,16 +11,17 @@ The image parser parses an image into an embeddable HTML element
var ImageParser = function(type,text,options) { var ImageParser = function(type,text,options) {
var element = { var element = {
type: "image", type: "element",
attributes: {} tag: "img",
}; attributes: {}
};
if(options._canonical_uri) { if(options._canonical_uri) {
element.attributes.source = {type: "string", value: options._canonical_uri}; element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) { } else if(text) {
if(type === "image/svg+xml" || type === ".svg") { if(type === "image/svg+xml" || type === ".svg") {
element.attributes.source = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)}; element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
} else { } else {
element.attributes.source = {type: "string", value: "data:" + type + ";base64," + text}; element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
} }
} }
this.tree = [element]; this.tree = [element];

View File

@@ -45,7 +45,7 @@ exports.parseWhiteSpace = function(source,pos) {
type: "whitespace", type: "whitespace",
start: pos, start: pos,
end: p end: p
}; }
} }
}; };
@@ -107,14 +107,13 @@ exports.parseStringLiteral = function(source,pos) {
type: "string", type: "string",
start: pos start: pos
}; };
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/g; var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')/g;
reString.lastIndex = pos; reString.lastIndex = pos;
var match = reString.exec(source); var match = reString.exec(source);
if(match && match.index === pos) { if(match && match.index === pos) {
node.value = match[1] !== undefined ? match[1] :( node.value = match[1] !== undefined ? match[1] :(
match[2] !== undefined ? match[2] : ( match[2] !== undefined ? match[2] : match[3]
match[3] !== undefined ? match[3] : match[4] );
));
node.end = pos + match[0].length; node.end = pos + match[0].length;
return node; return node;
} else { } else {
@@ -143,14 +142,7 @@ exports.parseParameterDefinition = function(paramString,options) {
var paramInfo = {name: paramMatch[1]}, var paramInfo = {name: paramMatch[1]},
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5]; defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
if(defaultValue !== undefined) { if(defaultValue !== undefined) {
// Check for an MVV reference ((varname)) paramInfo["default"] = defaultValue;
var mvvDefaultMatch = /^\(\(([^)|]+)\)\)$/.exec(defaultValue);
if(mvvDefaultMatch) {
paramInfo.defaultType = "multivalue-variable";
paramInfo.defaultVariable = mvvDefaultMatch[1];
} else {
paramInfo["default"] = defaultValue;
}
} }
params.push(paramInfo); params.push(paramInfo);
// Look for the next parameter // Look for the next parameter
@@ -170,7 +162,7 @@ exports.parseMacroParameters = function(node,source,pos) {
} }
node.end = pos; node.end = pos;
return node; return node;
}; }
/* /*
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:} Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
@@ -181,7 +173,7 @@ exports.parseMacroParameter = function(source,pos) {
start: pos start: pos
}; };
// Define our regexp // Define our regexp
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y; const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
// Skip whitespace // Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos); pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for the parameter // Look for the parameter
@@ -192,16 +184,16 @@ exports.parseMacroParameter = function(source,pos) {
pos = token.end; pos = token.end;
// Get the parameter details // Get the parameter details
node.value = token.match[2] !== undefined ? token.match[2] : ( node.value = token.match[2] !== undefined ? token.match[2] : (
token.match[3] !== undefined ? token.match[3] : ( token.match[3] !== undefined ? token.match[3] : (
token.match[4] !== undefined ? token.match[4] : ( token.match[4] !== undefined ? token.match[4] : (
token.match[5] !== undefined ? token.match[5] : ( token.match[5] !== undefined ? token.match[5] : (
token.match[6] !== undefined ? token.match[6] : ( token.match[6] !== undefined ? token.match[6] : (
"" ""
)
)
)
) )
) );
)
)
);
if(token.match[1]) { if(token.match[1]) {
node.name = token.match[1]; node.name = token.match[1];
} }
@@ -214,201 +206,28 @@ exports.parseMacroParameter = function(source,pos) {
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:} Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
*/ */
exports.parseMacroInvocationAsTransclusion = function(source,pos) { exports.parseMacroInvocationAsTransclusion = function(source,pos) {
var node = { var node = $tw.utils.parseMacroInvocation(source,pos);
type: "transclude", if(node) {
start: pos, var positionalName = 0,
attributes: {}, transclusion = {
orderedAttributes: [] type: "transclude",
}; start: node.start,
// Define our regexps end: node.end
var reVarName = /([^\s>"'=:]+)/g; };
// Skip whitespace $tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
pos = $tw.utils.skipWhiteSpace(source,pos); $tw.utils.each(node.params,function(param) {
// Look for a double opening angle bracket var name = param.name;
var token = $tw.utils.parseTokenString(source,pos,"<<"); if(name) {
if(!token) { if(name.charAt(0) === "$") {
return null; name = "$" + name;
}
pos = token.end;
// Get the variable name for the macro
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
if(!token) {
return null;
}
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
pos = token.end;
// Check that the tag is terminated by a space or >>
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
return null;
}
// Process attributes
pos = $tw.utils.parseMacroParametersAsAttributes(node,source,pos);
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double closing angle bracket
token = $tw.utils.parseTokenString(source,pos,">>");
if(!token) {
return null;
}
node.end = token.end;
return node;
};
/*
Look for an MVV (multi-valued variable) reference as a transclusion, i.e. ((varname)) or ((varname params))
Returns null if not found, or a parse tree node of type "transclude" with isMVV: true
*/
exports.parseMVVReferenceAsTransclusion = function(source,pos) {
var node = {
type: "transclude",
isMVV: true,
start: pos,
attributes: {},
orderedAttributes: []
};
// Define our regexps
var reVarName = /([^\s>"'=:)]+)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double opening parenthesis
var token = $tw.utils.parseTokenString(source,pos,"((");
if(!token) {
return null;
}
pos = token.end;
// Get the variable name
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
if(!token) {
return null;
}
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
pos = token.end;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a double closing parenthesis
token = $tw.utils.parseTokenString(source,pos,"))");
if(!token) {
return null;
}
node.end = token.end;
return node;
};
/*
Parse macro parameters as attributes. Returns the position after the last attribute
*/
exports.parseMacroParametersAsAttributes = function(node,source,pos) {
var position = 0,
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
while(attribute) {
if(!attribute.name) {
attribute.name = (position++) + "";
attribute.isPositional = true;
}
node.orderedAttributes.push(attribute);
node.attributes[attribute.name] = attribute;
pos = attribute.end;
// Get the next attribute
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
}
node.end = pos;
return pos;
};
/*
Parse a macro parameter as an attribute. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}, with the name being optional
*/
exports.parseMacroParameterAsAttribute = function(source,pos) {
var node = {
start: pos
};
// Define our regexps
var reAttributeName = /([^\/\s>"'`=:]+)/g,
reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/g,
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
reIndirectValue = /\{\{([^\}]+)\}\}/g,
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Get the attribute name and the separator token
var nameToken = $tw.utils.parseTokenRegExp(source,pos,reAttributeName),
namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end),
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/g),
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
// If we have a name and a separator then we have a named attribute
if(nameToken && separatorToken) {
node.name = nameToken.match[1];
// key value separator is `=` or `:`
node.assignmentOperator = separatorToken.match[0];
pos = separatorToken.end;
isNewStyleSeparator = (node.assignmentOperator === "=");
}
// Skip whitespace
pos = $tw.utils.skipWhiteSpace(source,pos);
// Look for a string literal
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
if(stringLiteral) {
pos = stringLiteral.end;
node.type = "string";
node.value = stringLiteral.value;
// Mark the value as having been quoted in the source
node.quoted = true;
} else {
// Look for a filtered value
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
if(filteredValue && isNewStyleSeparator) {
pos = filteredValue.end;
node.type = "filtered";
node.filter = filteredValue.match[1];
} else {
// Look for an indirect value
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
if(indirectValue && isNewStyleSeparator) {
pos = indirectValue.end;
node.type = "indirect";
node.textReference = indirectValue.match[1];
} else {
// Look for a macro invocation value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
if(macroInvocation && isNewStyleSeparator) {
pos = macroInvocation.end;
node.type = "macro";
node.value = macroInvocation;
} else {
// Look for an MVV reference value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
if(mvvReference && isNewStyleSeparator) {
pos = mvvReference.end;
node.type = "macro";
node.value = mvvReference;
node.isMVV = true;
} else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue && isNewStyleSeparator) {
pos = substitutedValue.end;
node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else {
// Look for a unquoted value
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
}
}
}
} }
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: name,type: "string", value: param.value, start: param.start, end: param.end});
} else {
$tw.utils.addAttributeToParseTreeNode(transclusion,{name: (positionalName++) + "",type: "string", value: param.value, start: param.start, end: param.end});
} }
} });
return transclusion;
} }
// Bail if we don't have a value
if(!node.type) {
return null;
}
// Update the end position
node.end = pos;
return node; return node;
}; };
@@ -477,7 +296,7 @@ exports.parseFilterVariable = function(source) {
}; };
/* /*
Look for an HTML attribute definition. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,} Look for an HTML attribute definition. Returns null if not found, otherwise returns {type: "attribute", name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
*/ */
exports.parseAttribute = function(source,pos) { exports.parseAttribute = function(source,pos) {
var node = { var node = {
@@ -527,20 +346,19 @@ exports.parseAttribute = function(source,pos) {
node.type = "indirect"; node.type = "indirect";
node.textReference = indirectValue.match[1]; node.textReference = indirectValue.match[1];
} else { } else {
// Look for a macro invocation value // Look for a unquoted value
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos); var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
if(macroInvocation) { if(unquotedValue) {
pos = macroInvocation.end; pos = unquotedValue.end;
node.type = "macro"; node.type = "string";
node.value = macroInvocation; node.value = unquotedValue.match[1];
} else { } else {
// Look for an MVV reference value // Look for a macro invocation value
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos); var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
if(mvvReference) { if(macroInvocation) {
pos = mvvReference.end; pos = macroInvocation.end;
node.type = "macro"; node.type = "macro";
node.value = mvvReference; node.value = macroInvocation;
node.isMVV = true;
} else { } else {
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue); var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
if(substitutedValue) { if(substitutedValue) {
@@ -548,16 +366,8 @@ exports.parseAttribute = function(source,pos) {
node.type = "substituted"; node.type = "substituted";
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2]; node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
} else { } else {
// Look for a unquoted value node.type = "string";
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute); node.value = "true";
if(unquotedValue) {
pos = unquotedValue.end;
node.type = "string";
node.value = unquotedValue.match[1];
} else {
node.type = "string";
node.value = "true";
}
} }
} }
} }
@@ -565,7 +375,6 @@ exports.parseAttribute = function(source,pos) {
} }
} }
} else { } else {
// If there is no equals sign or colon, then this is an attribute with no value, defaulting to "true"
node.type = "string"; node.type = "string";
node.value = "true"; node.value = "true";
} }

View File

@@ -11,10 +11,11 @@ The PDF parser embeds a PDF viewer
var ImageParser = function(type,text,options) { var ImageParser = function(type,text,options) {
var element = { var element = {
type: "element", type: "element",
tag: "iframe", tag: "iframe",
attributes: {} attributes: {}
}; },
src;
if(options._canonical_uri) { if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri}; element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) { } else if(text) {

View File

@@ -11,13 +11,14 @@ The video parser parses a video tiddler into an embeddable HTML element
var VideoParser = function(type,text,options) { var VideoParser = function(type,text,options) {
var element = { var element = {
type: "element", type: "element",
tag: "video", tag: "video",
attributes: { attributes: {
controls: {type: "string", value: "controls"}, controls: {type: "string", value: "controls"},
style: {type: "string", value: "width: 100%; object-fit: contain"} style: {type: "string", value: "width: 100%; object-fit: contain"}
} }
}; },
src;
if(options._canonical_uri) { if(options._canonical_uri) {
element.attributes.src = {type: "string", value: options._canonical_uri}; element.attributes.src = {type: "string", value: options._canonical_uri};
} else if(text) { } else if(text) {

View File

@@ -46,10 +46,10 @@ exports.parse = function() {
} }
// Return the $codeblock widget // Return the $codeblock widget
return [{ return [{
type: "codeblock", type: "codeblock",
attributes: { attributes: {
code: {type: "string", value: text, start: codeStart, end: this.parser.pos}, code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd} language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
} }
}]; }];
}; };

View File

@@ -51,10 +51,10 @@ exports.parse = function() {
var commentStart = this.match.index; var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length; var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{ return [{
type: "void", type: "void",
children: [], children: [],
text: this.parser.source.slice(commentStart, commentEnd), text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart, start: commentStart,
end: commentEnd end: commentEnd
}]; }];
}; };

View File

@@ -44,9 +44,9 @@ exports.parse = function() {
var commentStart = this.match.index; var commentStart = this.match.index;
var commentEnd = this.endMatch.index + this.endMatch[0].length; var commentEnd = this.endMatch.index + this.endMatch[0].length;
return [{ return [{
type: "void", type: "void",
text: this.parser.source.slice(commentStart, commentEnd), text: this.parser.source.slice(commentStart, commentEnd),
start: commentStart, start: commentStart,
end: commentEnd end: commentEnd
}]; }];
}; };

View File

@@ -95,7 +95,7 @@ exports.parseIfClause = function(filterCondition) {
hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g); hasLineBreak = !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
// If we found an else then we need to parse the body looking for the endif // If we found an else then we need to parse the body looking for the endif
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>", var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>",
ex; ex;
if(hasLineBreak) { if(hasLineBreak) {
ex = this.parser.parseBlocksTerminatedExtended(reEndString); ex = this.parser.parseBlocksTerminatedExtended(reEndString);
} else { } else {

View File

@@ -26,6 +26,8 @@ exports.init = function(parser) {
Parse the most recent match Parse the most recent match
*/ */
exports.parse = function() { exports.parse = function() {
// Get all the details of the match
var entityString = this.match[1];
// Move past the macro call // Move past the macro call
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Return the entity // Return the entity

View File

@@ -32,7 +32,7 @@ Instantiate parse rule
exports.init = function(parser) { exports.init = function(parser) {
this.parser = parser; this.parser = parser;
// Regexp to match // Regexp to match
this.matchRegExp = /\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*(?:\)\)[^)]*)*))?\)(\s*\r?\n)?/mg; this.matchRegExp = /\\(function|procedure|widget)\s+([^(\s]+)\((\s*([^)]*))?\)(\s*\r?\n)?/mg;
}; };
/* /*

View File

@@ -29,6 +29,7 @@ exports.init = function(parser) {
Parse the most recent match Parse the most recent match
*/ */
exports.parse = function() { exports.parse = function() {
var self = this;
// Move past the pragma invocation // Move past the pragma invocation
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
// Parse the filter terminated by a line break // Parse the filter terminated by a line break

View File

@@ -37,7 +37,7 @@ exports.parse = function() {
var paramString = this.match[2], var paramString = this.match[2],
params = []; params = [];
if(paramString !== "") { if(paramString !== "") {
var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[((?:[^\]]|\](?!\]))*)\]\]|([^"'\s]+)))?/mg, var reParam = /\s*([A-Za-z0-9\-_]+)(?:\s*:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|([^"'\s]+)))?/mg,
paramMatch = reParam.exec(paramString); paramMatch = reParam.exec(paramString);
while(paramMatch) { while(paramMatch) {
// Save the parameter details // Save the parameter details

View File

@@ -1,95 +0,0 @@
/*\
title: $:/core/modules/parsers/wikiparser/rules/mvvdisplayinline.js
type: application/javascript
module-type: wikirule
Wiki rule for inline display of multi-valued variables and filter results.
Variable display: ((varname)) or ((varname||separator))
Filter display: (((filter))) or (((filter||separator)))
The default separator is ", " (comma space).
\*/
"use strict";
exports.name = "mvvdisplayinline";
exports.types = {inline: true};
exports.init = function(parser) {
this.parser = parser;
};
exports.findNextMatch = function(startPos) {
var source = this.parser.source;
var nextStart = startPos;
while((nextStart = source.indexOf("((",nextStart)) >= 0) {
if(source.charAt(nextStart + 2) === "(") {
// Filter mode: (((filter))) or (((filter||sep)))
var match = /^\(\(\(([\s\S]+?)\)\)\)/.exec(source.substring(nextStart));
if(match) {
// Check for separator: split on last || before )))
var inner = match[1];
var sepIndex = inner.lastIndexOf("||");
if(sepIndex >= 0) {
this.nextMatch = {
type: "filter",
filter: inner.substring(0,sepIndex),
separator: inner.substring(sepIndex + 2),
start: nextStart,
end: nextStart + match[0].length
};
} else {
this.nextMatch = {
type: "filter",
filter: inner,
separator: ", ",
start: nextStart,
end: nextStart + match[0].length
};
}
return nextStart;
}
} else {
// Variable mode: ((varname)) or ((varname||sep))
var match = /^\(\(([^()|]+?)(?:\|\|([^)]*))?\)\)/.exec(source.substring(nextStart));
if(match) {
this.nextMatch = {
type: "variable",
varName: match[1],
separator: match[2] !== undefined ? match[2] : ", ",
start: nextStart,
end: nextStart + match[0].length
};
return nextStart;
}
}
nextStart += 2;
}
return undefined;
};
/*
Parse the most recent match
*/
exports.parse = function() {
var match = this.nextMatch;
this.nextMatch = null;
this.parser.pos = match.end;
var filter, sep = match.separator;
if(match.type === "variable") {
filter = "[(" + match.varName + ")join[" + sep + "]]";
} else {
filter = match.filter + " +[join[" + sep + "]]";
}
return [{
type: "text",
attributes: {
text: {name: "text", type: "filtered", filter: filter}
},
orderedAttributes: [
{name: "text", type: "filtered", filter: filter}
]
}];
};

View File

@@ -93,7 +93,7 @@ exports.parseLink = function(source,pos) {
splitPos = null; splitPos = null;
} }
// Pull out the tooltip and URL // Pull out the tooltip and URL
var URL, urlStart; var tooltip, URL, urlStart;
textNode.start = pos; textNode.start = pos;
if(splitPos) { if(splitPos) {
urlStart = splitPos + 1; urlStart = splitPos + 1;

View File

@@ -67,5 +67,5 @@ exports.parse = function() {
return [{ return [{
type: "void", type: "void",
children: tree children: tree
}]; }]
}; };

View File

@@ -60,7 +60,7 @@ var processRow = function(prevColumns) {
// End of row // End of row
if(prevCell && colSpanCount > 1) { if(prevCell && colSpanCount > 1) {
if(prevCell.attributes && prevCell.attributes && prevCell.attributes.colspan) { if(prevCell.attributes && prevCell.attributes && prevCell.attributes.colspan) {
colSpanCount += prevCell.attributes.colspan.value; colSpanCount += prevCell.attributes.colspan.value;
} else { } else {
colSpanCount -= 1; colSpanCount -= 1;
} }
@@ -163,7 +163,7 @@ exports.parse = function() {
table.children.splice(0,0,rowContainer); // Insert it at the bottom table.children.splice(0,0,rowContainer); // Insert it at the bottom
} }
// Set the alignment - TODO: figure out why TW did this // Set the alignment - TODO: figure out why TW did this
// rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom"; // rowContainer.attributes.align = rowCount === 0 ? "top" : "bottom";
// Parse the caption // Parse the caption
rowContainer.children = this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true}); rowContainer.children = this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true});
} else { } else {

View File

@@ -23,6 +23,27 @@ exports.init = function(parser) {
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg; this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}(?:\r?\n|$)/mg;
}; };
/*
Reject the match if we don't have a template or text reference
*/
exports.findNextMatch = function(startPos) {
this.matchRegExp.lastIndex = startPos;
this.match = this.matchRegExp.exec(this.parser.source);
if(this.match) {
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Bail if we don't have a template or text reference
if(!template && !textRef) {
return undefined;
} else {
return this.match.index;
}
} else {
return undefined;
}
return this.match ? this.match.index : undefined;
};
exports.parse = function() { exports.parse = function() {
// Move past the match // Move past the match
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
@@ -32,17 +53,17 @@ exports.parse = function() {
params = this.match[3] ? this.match[3].split("|") : []; params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget // Prepare the transclude widget
var transcludeNode = { var transcludeNode = {
type: "transclude", type: "transclude",
attributes: {}, attributes: {},
isBlock: true isBlock: true
}; };
$tw.utils.each(params,function(paramValue,index) { $tw.utils.each(params,function(paramValue,index) {
var name = "" + index; var name = "" + index;
transcludeNode.attributes[name] = { transcludeNode.attributes[name] = {
name: name, name: name,
type: "string", type: "string",
value: paramValue value: paramValue
}; }
}); });
// Prepare the tiddler widget // Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode; var tr, targetTitle, targetField, targetIndex, tiddlerNode;

View File

@@ -23,6 +23,27 @@ exports.init = function(parser) {
this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg; this.matchRegExp = /\{\{([^\{\}\|]*)(?:\|\|([^\|\{\}]+))?(?:\|([^\{\}]+))?\}\}/mg;
}; };
/*
Reject the match if we don't have a template or text reference
*/
exports.findNextMatch = function(startPos) {
this.matchRegExp.lastIndex = startPos;
this.match = this.matchRegExp.exec(this.parser.source);
if(this.match) {
var template = $tw.utils.trim(this.match[2]),
textRef = $tw.utils.trim(this.match[1]);
// Bail if we don't have a template or text reference
if(!template && !textRef) {
return undefined;
} else {
return this.match.index;
}
} else {
return undefined;
}
return this.match ? this.match.index : undefined;
};
exports.parse = function() { exports.parse = function() {
// Move past the match // Move past the match
this.parser.pos = this.matchRegExp.lastIndex; this.parser.pos = this.matchRegExp.lastIndex;
@@ -32,16 +53,16 @@ exports.parse = function() {
params = this.match[3] ? this.match[3].split("|") : []; params = this.match[3] ? this.match[3].split("|") : [];
// Prepare the transclude widget // Prepare the transclude widget
var transcludeNode = { var transcludeNode = {
type: "transclude", type: "transclude",
attributes: {} attributes: {}
}; };
$tw.utils.each(params,function(paramValue,index) { $tw.utils.each(params,function(paramValue,index) {
var name = "" + index; var name = "" + index;
transcludeNode.attributes[name] = { transcludeNode.attributes[name] = {
name: name, name: name,
type: "string", type: "string",
value: paramValue value: paramValue
}; }
}); });
// Prepare the tiddler widget // Prepare the tiddler widget
var tr, targetTitle, targetField, targetIndex, tiddlerNode; var tr, targetTitle, targetField, targetIndex, tiddlerNode;

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