mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-05-06 21:51:31 +00:00
Compare commits
180 Commits
element-ma
...
bidirectio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a80bd4a6f | ||
|
|
82bde9bffc | ||
|
|
ea84baa5a3 | ||
|
|
a4e4d36bf6 | ||
|
|
3ed481b2e2 | ||
|
|
27c60ff58d | ||
|
|
748ef8aa8d | ||
|
|
9cfa5a29fb | ||
|
|
5ea43ce212 | ||
|
|
df6bbbdedf | ||
|
|
37a461323e | ||
|
|
b29da7baac | ||
|
|
9830d4338c | ||
|
|
75b54457ed | ||
|
|
51f322c3c6 | ||
|
|
853af2d848 | ||
|
|
2c1cb33081 | ||
|
|
75267b730a | ||
|
|
2f63abc12a | ||
|
|
3bc78e6641 | ||
|
|
5f80256576 | ||
|
|
765386a4f9 | ||
|
|
ca8dcb690a | ||
|
|
99a00ab1b4 | ||
|
|
f95966d5bb | ||
|
|
3a20837c96 | ||
|
|
e3e49bb61e | ||
|
|
748969322b | ||
|
|
4611e3569f | ||
|
|
c1e145ca12 | ||
|
|
882504c8d1 | ||
|
|
b8f542458b | ||
|
|
aa837300d0 | ||
|
|
7f2baa17a9 | ||
|
|
39c6d8fb53 | ||
|
|
9afe5226f1 | ||
|
|
94aa37fe7e | ||
|
|
1e9c1ef82a | ||
|
|
6cde5e94ff | ||
|
|
fd0d3ccc27 | ||
|
|
1ad2e66cbc | ||
|
|
4699db9f89 | ||
|
|
d977b0ac5c | ||
|
|
7298684951 | ||
|
|
f78d8252af | ||
|
|
54260b5be8 | ||
|
|
95f12eb857 | ||
|
|
207a68cc59 | ||
|
|
b434b9d7ea | ||
|
|
b0013333de | ||
|
|
bcc30e305a | ||
|
|
34f4dfb903 | ||
|
|
32a3a3e478 | ||
|
|
c6520c4429 | ||
|
|
83d242fb2c | ||
|
|
ecafb7a4c0 | ||
|
|
0640e0abe2 | ||
|
|
a71ac56cc9 | ||
|
|
f518bdf27c | ||
|
|
0387b1100b | ||
|
|
c3a73fccd1 | ||
|
|
c25659d87c | ||
|
|
0c26a75472 | ||
|
|
a24dc0e9e8 | ||
|
|
a499ed0906 | ||
|
|
3cfb6b1202 | ||
|
|
ac769e5dcd | ||
|
|
ed01af8e47 | ||
|
|
92caa7312e | ||
|
|
478dce7009 | ||
|
|
f3c9cb2310 | ||
|
|
85fb634cae | ||
|
|
280701fbde | ||
|
|
01d3cde964 | ||
|
|
2ea3663ea7 | ||
|
|
78b6f6f442 | ||
|
|
3a4a8a206f | ||
|
|
aff5be7195 | ||
|
|
c4991a54a0 | ||
|
|
1d915389d9 | ||
|
|
f5b4b1781e | ||
|
|
65fcded29f | ||
|
|
962692c90c | ||
|
|
533414b1df | ||
|
|
ec27a4bf20 | ||
|
|
e1cf523e2c | ||
|
|
1ece822d7a | ||
|
|
b7a3418823 | ||
|
|
bb6d88f144 | ||
|
|
57c72756ef | ||
|
|
dda4c7fb10 | ||
|
|
fd3b96e2dd | ||
|
|
c07396c453 | ||
|
|
7fc255f90c | ||
|
|
4cd84a6ba1 | ||
|
|
fdfcd66c9b | ||
|
|
3983086b96 | ||
|
|
a61331e6ed | ||
|
|
8773a0433c | ||
|
|
846deb3039 | ||
|
|
111a168b0c | ||
|
|
02b4c04a56 | ||
|
|
9d5b5111d0 | ||
|
|
48cff401b2 | ||
|
|
7a866b93e3 | ||
|
|
b0d99f3bd3 | ||
|
|
91e7a62c13 | ||
|
|
9f7763710e | ||
|
|
b673651103 | ||
|
|
49faefcca5 | ||
|
|
75c26b46c6 | ||
|
|
add3d425b5 | ||
|
|
c23a0bedfd | ||
|
|
36b20e02a3 | ||
|
|
ab6172981c | ||
|
|
431b7fa3bf | ||
|
|
1c1f157079 | ||
|
|
ac19f300a9 | ||
|
|
9012b00806 | ||
|
|
a3acbaa2f1 | ||
|
|
07634d6595 | ||
|
|
785086e0a5 | ||
|
|
08f2b8bdf4 | ||
|
|
c305eb01eb | ||
|
|
71462143bf | ||
|
|
909149a347 | ||
|
|
8cd6bbc075 | ||
|
|
a2543cfd4a | ||
|
|
b713d13c5a | ||
|
|
bb05bd8817 | ||
|
|
42a908e1c9 | ||
|
|
70689a6de4 | ||
|
|
64ee20edd2 | ||
|
|
0177f09823 | ||
|
|
643cabf9c8 | ||
|
|
5cf3fcd843 | ||
|
|
67f13c585d | ||
|
|
1bbb7fd53b | ||
|
|
599933c34d | ||
|
|
b1ccb82e0a | ||
|
|
ea648c7d15 | ||
|
|
a3a4e91751 | ||
|
|
c96d398712 | ||
|
|
821dcaf002 | ||
|
|
9247a87e11 | ||
|
|
bda54b0ad5 | ||
|
|
cd8b1faa74 | ||
|
|
0673426f5a | ||
|
|
d376ada241 | ||
|
|
6fc65c1560 | ||
|
|
ab29f17d35 | ||
|
|
5ae4770317 | ||
|
|
33b2f514fb | ||
|
|
46fe3ca988 | ||
|
|
bf7c0b575c | ||
|
|
b236373064 | ||
|
|
d15398fc09 | ||
|
|
6bc77cf3e2 | ||
|
|
dc764b3a4a | ||
|
|
9c09841eda | ||
|
|
9d5be2e9f8 | ||
|
|
486d3bd326 | ||
|
|
196683915c | ||
|
|
42a3928960 | ||
|
|
2e76cc08a1 | ||
|
|
891e4fcb2b | ||
|
|
f6fd5ff261 | ||
|
|
526aaa3db8 | ||
|
|
455f1be3fb | ||
|
|
bffa0bb95a | ||
|
|
a1ef2ef6d4 | ||
|
|
75edd9b488 | ||
|
|
cde9c931c8 | ||
|
|
d07fe25cdb | ||
|
|
a40ce29451 | ||
|
|
75647eb623 | ||
|
|
70b4557738 | ||
|
|
efe58e41bc | ||
|
|
79e3d14698 | ||
|
|
763d717a13 |
16
.github/workflows/ci.yml
vendored
16
.github/workflows/ci.yml
vendored
@@ -5,17 +5,17 @@ on:
|
||||
- master
|
||||
- tiddlywiki-com
|
||||
env:
|
||||
NODE_VERSION: "22"
|
||||
NODE_VERSION: "22.22"
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/ci-test.sh"
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v7
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
@@ -30,8 +30,8 @@ jobs:
|
||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/ci-pre-build.sh"
|
||||
@@ -62,8 +62,8 @@ jobs:
|
||||
TW5_BUILD_OUTPUT: "./output"
|
||||
TW5_BUILD_ARCHIVE: "./output"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/ci-pre-build.sh"
|
||||
|
||||
4
.github/workflows/pr-check-build-size.yml
vendored
4
.github/workflows/pr-check-build-size.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
steps:
|
||||
- name: build-size-check
|
||||
id: get_sizes
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
uses: TiddlyWiki/cerebrus@v8.1
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
@@ -52,4 +52,4 @@ jobs:
|
||||
pr_size: '${{ needs.calculate-build-size.outputs.pr_size }}',
|
||||
base_size: '${{ needs.calculate-build-size.outputs.base_size }}'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
2
.github/workflows/pr-comment-build-size.yml
vendored
2
.github/workflows/pr-comment-build-size.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Build and check size
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
uses: TiddlyWiki/cerebrus@v8.1
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
||||
4
.github/workflows/pr-validation.yml
vendored
4
.github/workflows/pr-validation.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
steps:
|
||||
# Step 1: Validate PR paths
|
||||
- name: Validate PR Paths
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
uses: TiddlyWiki/cerebrus@v8.1
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
|
||||
# Step 2: Validate change notes
|
||||
- name: Validate Change Notes
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
uses: TiddlyWiki/cerebrus@v8.1
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -2,10 +2,20 @@
|
||||
.c9/
|
||||
.vs/
|
||||
.vscode/
|
||||
.claude/
|
||||
# TiddlyWiki
|
||||
tmp/
|
||||
output/
|
||||
node_modules/
|
||||
$__StoryList.tid
|
||||
# Playwright
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
$__StoryList.tid
|
||||
/playwright/.auth/
|
||||
test-screenshots/
|
||||
test-output.txt
|
||||
.playwright-mcp
|
||||
# TiddlyWiki MPC
|
||||
.tw-mcp
|
||||
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.4.0
|
||||
TW5_BUILD_VERSION=v5.5.0
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
@@ -120,7 +120,6 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
|| exit 1
|
||||
|
||||
# /empty.html Empty
|
||||
# /empty.hta For Internet Explorer
|
||||
# /empty-external-core.html External core empty
|
||||
# /tiddlywikicore-<version>.js Core plugin javascript
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
|
||||
@@ -45,7 +45,7 @@ git clone --depth=1 --branch=main "https://github.com/TiddlyWiki/tiddlywiki.org-
|
||||
|
||||
# Make the CNAME file that GitHub Pages requires
|
||||
|
||||
echo "tiddlywiki.org" > $TWORG_BUILD_OUTPUT/CNAME
|
||||
# echo "tiddlywiki.org" > $TWORG_BUILD_OUTPUT/CNAME
|
||||
|
||||
# Delete any existing static content
|
||||
|
||||
|
||||
@@ -15,40 +15,40 @@ var fs = require("fs"),
|
||||
{ optimize } = require("svgo"),
|
||||
config = {
|
||||
plugins: [
|
||||
'cleanupAttrs',
|
||||
'removeDoctype',
|
||||
'removeXMLProcInst',
|
||||
'removeComments',
|
||||
'removeMetadata',
|
||||
'removeTitle',
|
||||
'removeDesc',
|
||||
'removeUselessDefs',
|
||||
'removeEditorsNSData',
|
||||
'removeEmptyAttrs',
|
||||
'removeHiddenElems',
|
||||
'removeEmptyText',
|
||||
'removeEmptyContainers',
|
||||
"cleanupAttrs",
|
||||
"removeDoctype",
|
||||
"removeXMLProcInst",
|
||||
"removeComments",
|
||||
"removeMetadata",
|
||||
"removeTitle",
|
||||
"removeDesc",
|
||||
"removeUselessDefs",
|
||||
"removeEditorsNSData",
|
||||
"removeEmptyAttrs",
|
||||
"removeHiddenElems",
|
||||
"removeEmptyText",
|
||||
"removeEmptyContainers",
|
||||
// 'removeViewBox',
|
||||
'cleanupEnableBackground',
|
||||
'convertStyleToAttrs',
|
||||
'convertColors',
|
||||
'convertPathData',
|
||||
'convertTransform',
|
||||
'removeUnknownsAndDefaults',
|
||||
'removeNonInheritableGroupAttrs',
|
||||
'removeUselessStrokeAndFill',
|
||||
'removeUnusedNS',
|
||||
'cleanupIDs',
|
||||
'cleanupNumericValues',
|
||||
'moveElemsAttrsToGroup',
|
||||
'moveGroupAttrsToElems',
|
||||
'collapseGroups',
|
||||
"cleanupEnableBackground",
|
||||
"convertStyleToAttrs",
|
||||
"convertColors",
|
||||
"convertPathData",
|
||||
"convertTransform",
|
||||
"removeUnknownsAndDefaults",
|
||||
"removeNonInheritableGroupAttrs",
|
||||
"removeUselessStrokeAndFill",
|
||||
"removeUnusedNS",
|
||||
"cleanupIDs",
|
||||
"cleanupNumericValues",
|
||||
"moveElemsAttrsToGroup",
|
||||
"moveGroupAttrsToElems",
|
||||
"collapseGroups",
|
||||
// 'removeRasterImages',
|
||||
'mergePaths',
|
||||
'convertShapeToPath',
|
||||
'sortAttrs',
|
||||
"mergePaths",
|
||||
"convertShapeToPath",
|
||||
"sortAttrs",
|
||||
//'removeDimensions',
|
||||
{name: 'removeAttrs', params: { attrs: '(stroke|fill)' } }
|
||||
{name: "removeAttrs", params: { attrs: "(stroke|fill)" } }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ files.forEach(function(filename) {
|
||||
var newSVG = header.join("\n") + "\n\n" + result.data.replace("<<now "DD">>","<<now \"DD\">>");
|
||||
fs.writeFileSync(filepath,newSVG);
|
||||
} else {
|
||||
console.log("Error " + err + " with " + filename)
|
||||
console.log("Error " + err + " with " + filename);
|
||||
process.exit();
|
||||
};
|
||||
}
|
||||
|
||||
165
boot/boot.js
165
boot/boot.js
@@ -12,8 +12,6 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
|
||||
|
||||
var _boot = (function($tw) {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global modules: false, $tw: false */
|
||||
"use strict";
|
||||
|
||||
// Include bootprefix if we're not given module data
|
||||
@@ -37,7 +35,7 @@ if($tw.node) {
|
||||
$tw.boot.log = function(str) {
|
||||
$tw.boot.logMessages = $tw.boot.logMessages || [];
|
||||
$tw.boot.logMessages.push(str);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an object has a property
|
||||
@@ -47,7 +45,14 @@ $tw.utils.hop = function(object,property) {
|
||||
};
|
||||
|
||||
/** @deprecated Use Array.isArray instead */
|
||||
$tw.utils.isArray = value => Array.isArray(value);
|
||||
$tw.utils.isArray = (value) => Array.isArray(value);
|
||||
|
||||
/*
|
||||
Determine if a value is a date, even across VM boundaries
|
||||
*/
|
||||
$tw.utils.isDate = function(value) {
|
||||
return Object.prototype.toString.call(value) === "[object Date]";
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
@@ -126,9 +131,6 @@ $tw.utils.pushTop = function(array,value) {
|
||||
return array;
|
||||
};
|
||||
|
||||
/** @deprecated Use instanceof Date instead */
|
||||
$tw.utils.isDate = value => value instanceof Date;
|
||||
|
||||
/** @deprecated Use array iterative methods instead */
|
||||
$tw.utils.each = function(object,callback) {
|
||||
if(object) {
|
||||
@@ -138,7 +140,7 @@ $tw.utils.each = function(object,callback) {
|
||||
return next !== false;
|
||||
});
|
||||
} else {
|
||||
Object.entries(object).every(entry => {
|
||||
Object.entries(object).every((entry) => {
|
||||
const next = callback(entry[1], entry[0], object);
|
||||
return next !== false;
|
||||
});
|
||||
@@ -316,8 +318,25 @@ $tw.utils.htmlDecode = function(s) {
|
||||
return s.toString().replace(/</mg,"<").replace(/ /mg,"\xA0").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&");
|
||||
};
|
||||
|
||||
/** @deprecated Use window.location.hash instead. */
|
||||
$tw.utils.getLocationHash = () => window.location.hash;
|
||||
/*
|
||||
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 = 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 */
|
||||
$tw.utils.pad = function(value,length = 2) {
|
||||
@@ -548,7 +567,7 @@ using a lowercase extension only.
|
||||
*/
|
||||
$tw.utils.getFileExtensionInfo = function(ext) {
|
||||
return ext ? $tw.config.fileExtensionInfo[ext.toLowerCase()] : null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Given an extension, get the correct encoding for that file.
|
||||
@@ -571,7 +590,7 @@ var globalCheck =[
|
||||
" delete Object.prototype.__temp__;",
|
||||
" }",
|
||||
" delete Object.prototype.__temp__;",
|
||||
].join('\n');
|
||||
].join("\n");
|
||||
|
||||
/*
|
||||
Run code globally with specified context variables in scope
|
||||
@@ -596,10 +615,10 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||
// Compile the code into a function
|
||||
var fn;
|
||||
if($tw.browser) {
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
|
||||
fn = Function("return " + code + "\n\n//# sourceURL=" + filename)(); // See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
|
||||
} else {
|
||||
if(sandbox){
|
||||
fn = vm.runInContext(code,sandbox,filename)
|
||||
fn = vm.runInContext(code,sandbox,filename);
|
||||
} else {
|
||||
fn = vm.runInThisContext(code,filename);
|
||||
}
|
||||
@@ -710,7 +729,7 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
var self = this;
|
||||
form.addEventListener("submit",function(event) {
|
||||
// Collect the form data
|
||||
var data = {},t;
|
||||
var data = {};
|
||||
$tw.utils.each(form.elements,function(element) {
|
||||
if(element.name && element.value) {
|
||||
data[element.name] = element.value;
|
||||
@@ -756,7 +775,7 @@ $tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
|
||||
promptInfo.form.parentNode.removeChild(promptInfo.form);
|
||||
this.setWrapperDisplay();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Crypto helper object for encrypted content. It maintains the password text in a closure, and provides methods to change
|
||||
@@ -795,7 +814,7 @@ $tw.utils.Crypto = function() {
|
||||
};
|
||||
this.hasPassword = function() {
|
||||
return !!currentPassword;
|
||||
}
|
||||
};
|
||||
this.encrypt = function(text,password) {
|
||||
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
|
||||
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
|
||||
@@ -813,7 +832,7 @@ Execute the module named 'moduleName'. The name can optionally be relative to th
|
||||
$tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
var name = moduleName;
|
||||
if(moduleName.charAt(0) === ".") {
|
||||
name = $tw.utils.resolvePath(moduleName,moduleRoot)
|
||||
name = $tw.utils.resolvePath(moduleName,moduleRoot);
|
||||
}
|
||||
if(!$tw.modules.titles[name]) {
|
||||
if($tw.modules.titles[name + ".js"]) {
|
||||
@@ -874,7 +893,6 @@ $tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
if(!moduleInfo) {
|
||||
// We could not find the module on this path
|
||||
// Try to defer to browserify etc, or node
|
||||
var deferredModule;
|
||||
if($tw.browser) {
|
||||
if(window.require) {
|
||||
try {
|
||||
@@ -1129,8 +1147,7 @@ enableIndexers - Array of indexer names to enable, or null to use all available
|
||||
*/
|
||||
$tw.Wiki = function(options) {
|
||||
options = options || {};
|
||||
var self = this,
|
||||
tiddlers = Object.create(null), // Hashmap of tiddlers
|
||||
var tiddlers = Object.create(null), // Hashmap of tiddlers
|
||||
tiddlerTitles = null, // Array of tiddler titles
|
||||
getTiddlerTitles = function() {
|
||||
if(!tiddlerTitles) {
|
||||
@@ -1184,7 +1201,7 @@ $tw.Wiki = function(options) {
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
}
|
||||
};
|
||||
// Save the new tiddler
|
||||
tiddlers[title] = tiddler;
|
||||
// Check we've got the title
|
||||
@@ -1194,7 +1211,7 @@ $tw.Wiki = function(options) {
|
||||
tiddler: tiddler,
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
};
|
||||
// Update indexes
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
@@ -1219,7 +1236,7 @@ $tw.Wiki = function(options) {
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
}
|
||||
};
|
||||
// Delete the tiddler
|
||||
delete tiddlers[title];
|
||||
// Delete it from the list of titles
|
||||
@@ -1234,7 +1251,7 @@ $tw.Wiki = function(options) {
|
||||
tiddler: this.getTiddler(title),
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
};
|
||||
// Update indexes
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
@@ -1422,8 +1439,7 @@ $tw.Wiki = function(options) {
|
||||
|
||||
// Unregister the plugin tiddlers of a particular type, or null/undefined for any type, optionally restricting unregistering to an array of tiddler titles. Returns an array of the titles affected
|
||||
this.unregisterPluginTiddlers = function(pluginType,titles) {
|
||||
var self = this,
|
||||
unregisteredTitles = [];
|
||||
var unregisteredTitles = [];
|
||||
// Remove any previous registered plugins of this type
|
||||
for(var t=pluginTiddlers.length-1; t>=0; t--) {
|
||||
var tiddler = pluginTiddlers[t];
|
||||
@@ -1437,16 +1453,15 @@ $tw.Wiki = function(options) {
|
||||
|
||||
// Unpack the currently registered plugins, creating shadow tiddlers for their constituent tiddlers
|
||||
this.unpackPluginTiddlers = function() {
|
||||
var self = this;
|
||||
// Sort the plugin titles by the `plugin-priority` field, if this field is missing, default to 1
|
||||
pluginTiddlers.sort(function(a, b) {
|
||||
var priorityA = "plugin-priority" in a.fields ? a.fields["plugin-priority"] : 1;
|
||||
var priorityB = "plugin-priority" in b.fields ? b.fields["plugin-priority"] : 1;
|
||||
if (priorityA !== priorityB) {
|
||||
if(priorityA !== priorityB) {
|
||||
return priorityA - priorityB;
|
||||
} else if (a.fields.title < b.fields.title) {
|
||||
} else if(a.fields.title < b.fields.title) {
|
||||
return -1;
|
||||
} else if (a.fields.title === b.fields.title) {
|
||||
} else if(a.fields.title === b.fields.title) {
|
||||
return 0;
|
||||
} else {
|
||||
return +1;
|
||||
@@ -1524,8 +1539,8 @@ Register all the module tiddlers that have a module type
|
||||
$tw.Wiki.prototype.defineShadowModules = function() {
|
||||
var self = this;
|
||||
this.eachShadow(function(tiddler,title) {
|
||||
// Don't define the module if it is overidden by an ordinary tiddler
|
||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||
// Don't define the module if it is overidden by an ordinary tiddler, or has already been defined
|
||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type") && !$tw.utils.hop($tw.modules.titles,title)) {
|
||||
if(tiddler.hasField("draft.of")) {
|
||||
// Report a fundamental problem
|
||||
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
|
||||
@@ -1553,7 +1568,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
|
||||
// Assemble a report tiddler
|
||||
var titleReportTiddler = "TiddlyWiki Safe Mode",
|
||||
report = [];
|
||||
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:")
|
||||
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:");
|
||||
// Delete the overrides
|
||||
overrides.forEach(function(title) {
|
||||
var tiddler = self.getTiddler(title),
|
||||
@@ -1562,7 +1577,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
|
||||
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
|
||||
report.push("* [[" + title + "|" + newTitle + "]]");
|
||||
});
|
||||
report.push()
|
||||
report.push();
|
||||
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
|
||||
// Set $:/DefaultTiddlers to point to our report
|
||||
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
|
||||
@@ -1956,7 +1971,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
});
|
||||
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath,dynamicStoreId) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
@@ -1996,7 +2011,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
|
||||
break;
|
||||
case "filepath":
|
||||
value = path.relative(rootPath, filename).split(path.sep).join('/');
|
||||
value = path.relative(rootPath, filename).split(path.sep).join("/");
|
||||
break;
|
||||
case "filename":
|
||||
value = path.basename(filename);
|
||||
@@ -2031,9 +2046,9 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
});
|
||||
});
|
||||
if(isEditableFile) {
|
||||
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, isEditableFile: true, tiddlers: fileTiddlers});
|
||||
tiddlers.push({filepath: pathname, hasMetaFile: !!metadata && !isTiddlerFile, isEditableFile: true, dynamicStoreId: dynamicStoreId, tiddlers: fileTiddlers});
|
||||
} else {
|
||||
tiddlers.push({tiddlers: fileTiddlers});
|
||||
tiddlers.push({dynamicStoreId: dynamicStoreId, tiddlers: fileTiddlers});
|
||||
}
|
||||
};
|
||||
// Helper to recursively search subdirectories
|
||||
@@ -2049,7 +2064,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
}
|
||||
});
|
||||
return arrayOfFiles;
|
||||
}
|
||||
};
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
if(tidInfo.prefix && tidInfo.suffix) {
|
||||
@@ -2074,6 +2089,31 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
// Process directory specifier
|
||||
var dirPath = path.resolve(filepath,dirSpec.path);
|
||||
if(fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
||||
// Register a dynamic store if requested
|
||||
var dynamicStoreId = null;
|
||||
if(dirSpec.dynamicStore && $tw.boot.dynamicStores) {
|
||||
dynamicStoreId = dirPath;
|
||||
var existing = null;
|
||||
for(var ds=0; ds<$tw.boot.dynamicStores.length; ds++) {
|
||||
if($tw.boot.dynamicStores[ds].id === dynamicStoreId) {
|
||||
existing = $tw.boot.dynamicStores[ds];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!existing) {
|
||||
$tw.boot.dynamicStores.push({
|
||||
id: dynamicStoreId,
|
||||
directory: dirPath,
|
||||
saveFilter: dirSpec.dynamicStore.saveFilter || "",
|
||||
watch: dirSpec.dynamicStore.watch !== false,
|
||||
debounce: dirSpec.dynamicStore.debounce || 400,
|
||||
filesRegExp: dirSpec.filesRegExp || "^.*$",
|
||||
searchSubdirectories: !!dirSpec.searchSubdirectories,
|
||||
isTiddlerFile: !!dirSpec.isTiddlerFile,
|
||||
fields: dirSpec.fields || {}
|
||||
});
|
||||
}
|
||||
}
|
||||
var files = getAllFiles(dirPath, dirSpec.searchSubdirectories),
|
||||
fileRegExp = new RegExp(dirSpec.filesRegExp || "^.*$"),
|
||||
metaRegExp = /^.*\.meta$/;
|
||||
@@ -2082,7 +2122,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
dirSpec.fields = dirSpec.fields || {};
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile || !!dirSpec.dynamicStore,dirSpec.path,dynamicStoreId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2158,7 +2198,7 @@ Returns the path of the plugin folder
|
||||
$tw.findLibraryItem = function(name,paths) {
|
||||
var pathIndex = 0;
|
||||
do {
|
||||
var pluginPath = path.resolve(paths[pathIndex],"./" + name)
|
||||
var pluginPath = path.resolve(paths[pathIndex],"./" + name);
|
||||
if(fs.existsSync(pluginPath) && fs.statSync(pluginPath).isDirectory()) {
|
||||
return pluginPath;
|
||||
}
|
||||
@@ -2269,6 +2309,24 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
||||
$tw.loadPlugins(wikiInfo.plugins,$tw.config.pluginsPath,$tw.config.pluginsEnvVar);
|
||||
$tw.loadPlugins(wikiInfo.themes,$tw.config.themesPath,$tw.config.themesEnvVar);
|
||||
$tw.loadPlugins(wikiInfo.languages,$tw.config.languagesPath,$tw.config.languagesEnvVar);
|
||||
// Register plugin-provided tiddlerdeserializer and tiddlerserializer modules now,
|
||||
// so they are available when the wiki tiddler files are read from disk below.
|
||||
// We also apply the supporting `utils`, `tiddlerfield`, and `tiddlermethod`
|
||||
// modules so deserializers can call into them (e.g. core's text/html
|
||||
// deserializer needs $tw.utils.extractEncryptedStoreArea).
|
||||
// (All of these steps run again later in execStartup; they are idempotent.)
|
||||
$tw.wiki.readPluginInfo();
|
||||
$tw.wiki.registerPluginTiddlers("plugin");
|
||||
$tw.wiki.unpackPluginTiddlers();
|
||||
$tw.wiki.defineShadowModules();
|
||||
$tw.modules.applyMethods("utils",$tw.utils);
|
||||
if($tw.node) {
|
||||
$tw.modules.applyMethods("utils-node",$tw.utils);
|
||||
}
|
||||
$tw.Tiddler.fieldModules = $tw.modules.getModulesByTypeAsHashmap("tiddlerfield");
|
||||
$tw.modules.applyMethods("tiddlermethod",$tw.Tiddler.prototype);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
$tw.modules.applyMethods("tiddlerserializer",$tw.Wiki.tiddlerSerializerModules);
|
||||
// Load the wiki files, registering them as writable
|
||||
var resolvedWikiPath = path.resolve(wikiPath,$tw.config.wikiTiddlersSubDir);
|
||||
$tw.utils.each($tw.loadTiddlersFromPath(resolvedWikiPath),function(tiddlerFile) {
|
||||
@@ -2278,7 +2336,8 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
||||
filepath: tiddlerFile.filepath,
|
||||
type: tiddlerFile.type,
|
||||
hasMetaFile: tiddlerFile.hasMetaFile,
|
||||
isEditableFile: config["retain-original-tiddler-path"] || tiddlerFile.isEditableFile || tiddlerFile.filepath.indexOf($tw.boot.wikiTiddlersPath) !== 0
|
||||
isEditableFile: config["retain-original-tiddler-path"] || tiddlerFile.isEditableFile || tiddlerFile.filepath.indexOf($tw.boot.wikiTiddlersPath) !== 0,
|
||||
dynamicStoreId: tiddlerFile.dynamicStoreId || null
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -2290,7 +2349,10 @@ $tw.loadWikiTiddlers = function(wikiPath,options) {
|
||||
for(var title in $tw.boot.files) {
|
||||
fileInfo = $tw.boot.files[title];
|
||||
if(fileInfo.isEditableFile) {
|
||||
relativePath = path.relative($tw.boot.wikiTiddlersPath,fileInfo.filepath);
|
||||
// For tiddlers loaded from a dynamic store, compute originalpath relative to the store's directory
|
||||
// so that save-time path resolution against that directory yields the correct location.
|
||||
var basePath = fileInfo.dynamicStoreId || $tw.boot.wikiTiddlersPath;
|
||||
relativePath = path.relative(basePath,fileInfo.filepath);
|
||||
fileInfo.originalpath = relativePath;
|
||||
output[title] =
|
||||
path.sep === "/" ?
|
||||
@@ -2416,6 +2478,8 @@ $tw.boot.initStartup = function(options) {
|
||||
if(!$tw.boot.tasks.readBrowserTiddlers) {
|
||||
// For writable tiddler files, a hashmap of title to {filepath:,type:,hasMetaFile:}
|
||||
$tw.boot.files = Object.create(null);
|
||||
// Array of {id, directory, saveFilter, watch, debounce} registered via tiddlywiki.files dynamicStore directives
|
||||
$tw.boot.dynamicStores = [];
|
||||
// System paths and filenames
|
||||
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
||||
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
||||
@@ -2505,6 +2569,9 @@ $tw.boot.initStartup = function(options) {
|
||||
// Install the tiddler deserializer modules
|
||||
$tw.Wiki.tiddlerDeserializerModules = Object.create(null);
|
||||
$tw.modules.applyMethods("tiddlerdeserializer",$tw.Wiki.tiddlerDeserializerModules);
|
||||
// Install the tiddler serializer modules
|
||||
$tw.Wiki.tiddlerSerializerModules = Object.create(null);
|
||||
$tw.modules.applyMethods("tiddlerserializer",$tw.Wiki.tiddlerSerializerModules);
|
||||
// Call unload handlers in the browser
|
||||
if($tw.browser) {
|
||||
window.onbeforeunload = function(event) {
|
||||
@@ -2517,7 +2584,7 @@ $tw.boot.initStartup = function(options) {
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
$tw.boot.loadStartup = function(options){
|
||||
@@ -2534,7 +2601,7 @@ $tw.boot.loadStartup = function(options){
|
||||
}
|
||||
// Give hooks a chance to modify the store
|
||||
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
|
||||
}
|
||||
};
|
||||
$tw.boot.execStartup = function(options){
|
||||
// Unpack plugin tiddlers
|
||||
$tw.wiki.readPluginInfo();
|
||||
@@ -2564,7 +2631,7 @@ $tw.boot.execStartup = function(options){
|
||||
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
|
||||
// Repeatedly execute the next eligible task
|
||||
$tw.boot.executeNextStartupTask(options.callback);
|
||||
}
|
||||
};
|
||||
/*
|
||||
Startup TiddlyWiki
|
||||
*/
|
||||
@@ -2583,7 +2650,7 @@ $tw.addUnloadTask = function(task) {
|
||||
if($tw.unloadTasks.indexOf(task) === -1) {
|
||||
$tw.unloadTasks.push(task);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the remaining eligible startup tasks
|
||||
@@ -2630,7 +2697,7 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
||||
}
|
||||
taskIndex++;
|
||||
}
|
||||
if(typeof callback === 'function') {
|
||||
if(typeof callback === "function") {
|
||||
callback();
|
||||
}
|
||||
return false;
|
||||
|
||||
16
community/people/SaqImtiaz.tid
Normal file
16
community/people/SaqImtiaz.tid
Normal file
File diff suppressed because one or more lines are too long
7
community/people/kjharcombe.tid
Normal file
7
community/people/kjharcombe.tid
Normal file
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
|
||||
created: 20250909171928024
|
||||
modified: 20251110133437795
|
||||
tags: Community/Team
|
||||
leader: @kjharcombe
|
||||
team: @MotovunJack
|
||||
title: Infrastructure Team
|
||||
|
||||
@@ -12,4 +13,4 @@ The infrastructure includes:
|
||||
* github.com/TiddlyWiki
|
||||
* tiddlywiki.com DNS
|
||||
* Netlify account for PR previews
|
||||
* edit.tiddlywiki.com
|
||||
* edit.tiddlywiki.com
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -103,7 +103,7 @@ Commander.prototype.executeNextCommand = function() {
|
||||
c = new command.Command(params,this);
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||
err.then((e) => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||
} else if(err) {
|
||||
this.callback(err);
|
||||
} else {
|
||||
@@ -120,7 +120,7 @@ Commander.prototype.executeNextCommand = function() {
|
||||
});
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { if(e) this.callback(e); });
|
||||
err.then((e) => { if(e) this.callback(e); });
|
||||
} else if(err) {
|
||||
this.callback(err);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ Command.prototype.execute = function() {
|
||||
if(!filter) {
|
||||
return "No filter specified";
|
||||
}
|
||||
var commands = this.commander.wiki.filterTiddlers(filter)
|
||||
var commands = this.commander.wiki.filterTiddlers(filter);
|
||||
if(commands.length === 0) {
|
||||
return "No tiddlers found for filter '" + filter + "'";
|
||||
}
|
||||
|
||||
@@ -24,8 +24,7 @@ Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filter";
|
||||
}
|
||||
var self = this,
|
||||
wiki = this.commander.wiki,
|
||||
var wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
tiddlers = wiki.filterTiddlers(filter);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
|
||||
@@ -66,7 +66,7 @@ Command.prototype.fetchFiles = function(options) {
|
||||
// Get the list of URLs
|
||||
var urls;
|
||||
if(options.url) {
|
||||
urls = [options.url]
|
||||
urls = [options.url];
|
||||
} else if(options.urlFilter) {
|
||||
urls = this.commander.wiki.filterTiddlers(options.urlFilter);
|
||||
} else {
|
||||
@@ -96,30 +96,30 @@ Command.prototype.fetchFile = function(url,options,callback,redirectCount) {
|
||||
var self = this,
|
||||
lib = url.substr(0,8) === "https://" ? require("https") : require("http");
|
||||
lib.get(url).on("response",function(response) {
|
||||
var type = (response.headers["content-type"] || "").split(";")[0],
|
||||
data = [];
|
||||
self.commander.write("Reading " + url + ": ");
|
||||
response.on("data",function(chunk) {
|
||||
data.push(chunk);
|
||||
self.commander.write(".");
|
||||
});
|
||||
response.on("end",function() {
|
||||
self.commander.write("\n");
|
||||
if(response.statusCode === 200) {
|
||||
self.processBody(Buffer.concat(data),type,options,url);
|
||||
callback(null);
|
||||
} else {
|
||||
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
|
||||
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
|
||||
} else {
|
||||
return callback("Error " + response.statusCode + " retrieving " + url)
|
||||
}
|
||||
}
|
||||
});
|
||||
response.on("error",function(e) {
|
||||
var type = (response.headers["content-type"] || "").split(";")[0],
|
||||
data = [];
|
||||
self.commander.write("Reading " + url + ": ");
|
||||
response.on("data",function(chunk) {
|
||||
data.push(chunk);
|
||||
self.commander.write(".");
|
||||
});
|
||||
response.on("end",function() {
|
||||
self.commander.write("\n");
|
||||
if(response.statusCode === 200) {
|
||||
self.processBody(Buffer.concat(data),type,options,url);
|
||||
callback(null);
|
||||
} else {
|
||||
if(response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
|
||||
return self.fetchFile(response.headers.location,options,callback,redirectCount + 1);
|
||||
} else {
|
||||
return callback("Error " + response.statusCode + " retrieving " + url);
|
||||
}
|
||||
}
|
||||
});
|
||||
response.on("error",function(e) {
|
||||
console.log("Error on GET request: " + e);
|
||||
callback(e);
|
||||
});
|
||||
});
|
||||
});
|
||||
return null;
|
||||
};
|
||||
@@ -153,18 +153,18 @@ Command.prototype.processBody = function(body,type,options,url) {
|
||||
if(options.transformFilter) {
|
||||
var transformedTitle = (incomingWiki.filterTiddlers(options.transformFilter,null,self.commander.wiki.makeTiddlerIterator([title])) || [""])[0];
|
||||
if(transformedTitle) {
|
||||
self.commander.log("Importing " + title + " as " + transformedTitle)
|
||||
self.commander.log("Importing " + title + " as " + transformedTitle);
|
||||
newTiddler = new $tw.Tiddler(tiddler,{title: transformedTitle});
|
||||
}
|
||||
} else {
|
||||
self.commander.log("Importing " + title)
|
||||
self.commander.log("Importing " + title);
|
||||
newTiddler = tiddler;
|
||||
}
|
||||
self.commander.wiki.importTiddler(newTiddler);
|
||||
count++;
|
||||
}
|
||||
});
|
||||
self.commander.log("Imported " + count + " tiddlers")
|
||||
self.commander.log("Imported " + count + " tiddlers");
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
@@ -22,8 +22,7 @@ var Command = function(params,commander,callback) {
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path");
|
||||
fs = require("fs");
|
||||
if(this.params.length < 2) {
|
||||
return "Missing parameters";
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@ var Command = function(params,commander) {
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
var fs = require("fs");
|
||||
// Check that we don't already have a valid wiki folder
|
||||
if($tw.boot.wikiTiddlersPath || ($tw.utils.isDirectory($tw.boot.wikiPath) && !$tw.utils.isDirectoryEmpty($tw.boot.wikiPath))) {
|
||||
return "Wiki folder is not empty";
|
||||
|
||||
@@ -19,7 +19,6 @@ exports.info = {
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
var self = this;
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
|
||||
@@ -21,9 +21,7 @@ var Command = function(params,commander,callback) {
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path");
|
||||
var self = this;
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename";
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@ var Command = function(params,commander,callback) {
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
var path = require("path");
|
||||
if(this.params.length < 1) {
|
||||
return "Missing output path";
|
||||
}
|
||||
|
||||
@@ -7,59 +7,57 @@ Render individual tiddlers and save the results to the specified files
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
exports.info = {
|
||||
name: "render",
|
||||
synchronous: true
|
||||
};
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing tiddler filter";
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
|
||||
if(filenameResults.length > 0) {
|
||||
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
} else {
|
||||
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
|
||||
}
|
||||
var self = this,
|
||||
fs = require("fs"),
|
||||
path = require("path"),
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]addsuffix[.html]]",
|
||||
type = this.params[2] || "text/html",
|
||||
template = this.params[3],
|
||||
variableList = this.params.slice(4),
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter),
|
||||
variables = Object.create(null);
|
||||
while(variableList.length >= 2) {
|
||||
variables[variableList[0]] = variableList[1];
|
||||
variableList = variableList.slice(2);
|
||||
}
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
var filenameResults = wiki.filterTiddlers(filenameFilter,$tw.rootWidget,wiki.makeTiddlerIterator([title]));
|
||||
if(filenameResults.length > 0) {
|
||||
var filepath = path.resolve(self.commander.outputPath,filenameResults[0]);
|
||||
if(self.commander.verbose) {
|
||||
console.log("Rendering \"" + title + "\" to \"" + filepath + "\"");
|
||||
}
|
||||
var parser = wiki.parseTiddler(template || title),
|
||||
widgetNode = wiki.makeWidget(parser,{variables: $tw.utils.extend({},variables,{currentTiddler: title,storyTiddler: title})}),
|
||||
container = $tw.fakeDocument.createElement("div");
|
||||
widgetNode.render(container,null);
|
||||
var text = type === "text/html" ? container.innerHTML : container.textContent;
|
||||
$tw.utils.createFileDirectories(filepath);
|
||||
fs.writeFileSync(filepath,text,"utf8");
|
||||
} else {
|
||||
console.log("Not rendering \"" + title + "\" because the filename filter returned an empty result");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
};
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
exports.Command = Command;
|
||||
|
||||
@@ -9,8 +9,6 @@ Command to render several tiddlers to a folder of files
|
||||
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "rendertiddlers",
|
||||
synchronous: true
|
||||
|
||||
@@ -7,57 +7,56 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "save",
|
||||
synchronous: true
|
||||
};
|
||||
exports.info = {
|
||||
name: "save",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename filter";
|
||||
}
|
||||
var self = this,
|
||||
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 + "\"");
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename filter";
|
||||
}
|
||||
var self = this,
|
||||
path = require("path"),
|
||||
result = null,
|
||||
wiki = this.commander.wiki,
|
||||
tiddlerFilter = this.params[0],
|
||||
filenameFilter = this.params[1] || "[is[tiddler]]",
|
||||
tiddlers = wiki.filterTiddlers(tiddlerFilter);
|
||||
$tw.utils.each(tiddlers,function(title) {
|
||||
if(!result) {
|
||||
var tiddler = self.commander.wiki.getTiddler(title);
|
||||
if(tiddler) {
|
||||
var fileInfo = $tw.utils.generateTiddlerFileInfo(tiddler,{
|
||||
directory: path.resolve(self.commander.outputPath),
|
||||
pathFilters: [filenameFilter],
|
||||
wiki: wiki,
|
||||
fileInfo: {
|
||||
overwrite: true
|
||||
}
|
||||
try {
|
||||
$tw.utils.saveTiddlerToFileSync(tiddler,fileInfo);
|
||||
} catch (err) {
|
||||
result = "Error saving tiddler \"" + title + "\", to file: \"" + fileInfo.filepath + "\"";
|
||||
}
|
||||
} else {
|
||||
result = "Tiddler '" + title + "' not found";
|
||||
});
|
||||
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;
|
||||
};
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
exports.Command = Command;
|
||||
|
||||
@@ -9,8 +9,6 @@ Command to save several tiddlers to a folder of files
|
||||
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "savetiddlers",
|
||||
synchronous: true
|
||||
|
||||
@@ -43,7 +43,7 @@ Command.prototype.execute = function() {
|
||||
namedParames,
|
||||
tiddlerFilter,
|
||||
options = {};
|
||||
if (regFilter.test(this.params[1])) {
|
||||
if(regFilter.test(this.params[1])) {
|
||||
namedParames = this.commander.extractNamedParameters(this.params.slice(1));
|
||||
tiddlerFilter = namedParames.filter || "[all[tiddlers]]";
|
||||
} else {
|
||||
@@ -177,13 +177,13 @@ WikiFolderMaker.prototype.saveCustomPlugin = function(pluginTiddler) {
|
||||
$tw.utils.each(pluginTiddlers,function(tiddler,title) {
|
||||
if(!tiddler.title) {
|
||||
tiddler.title = title;
|
||||
}
|
||||
}
|
||||
self.saveTiddler(directory,new $tw.Tiddler(tiddler));
|
||||
});
|
||||
};
|
||||
|
||||
WikiFolderMaker.prototype.saveTiddler = function(directory,tiddler) {
|
||||
var title = tiddler.fields.title, fileInfo, pathFilters, extFilters;
|
||||
var fileInfo, pathFilters, extFilters;
|
||||
if(this.wiki.tiddlerExists("$:/config/FileSystemPaths")) {
|
||||
pathFilters = this.wiki.getTiddlerText("$:/config/FileSystemPaths","").split("\n");
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ exports.info = {
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
var self = this;
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
|
||||
@@ -9,8 +9,6 @@ Command to modify selected tiddlers to set a field to the text of a template tid
|
||||
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
|
||||
exports.info = {
|
||||
name: "setfield",
|
||||
synchronous: true
|
||||
@@ -26,8 +24,7 @@ Command.prototype.execute = function() {
|
||||
if(this.params.length < 4) {
|
||||
return "Missing parameters";
|
||||
}
|
||||
var self = this,
|
||||
wiki = this.commander.wiki,
|
||||
var wiki = this.commander.wiki,
|
||||
filter = this.params[0],
|
||||
fieldname = this.params[1] || "text",
|
||||
templatetitle = this.params[2],
|
||||
|
||||
@@ -26,7 +26,7 @@ exports.getSubdirectories = function(dirPath) {
|
||||
}
|
||||
});
|
||||
return subdirs;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Recursively (and synchronously) copy a directory and all its content
|
||||
@@ -46,8 +46,7 @@ exports.copyDirectory = function(srcPath,dstPath) {
|
||||
}
|
||||
// Function to copy a folder full of files
|
||||
var copy = function(srcPath,dstPath) {
|
||||
var srcStats = fs.lstatSync(srcPath),
|
||||
dstExists = fs.existsSync(dstPath);
|
||||
var srcStats = fs.lstatSync(srcPath);
|
||||
if(srcStats.isFile()) {
|
||||
$tw.utils.copyFile(srcPath,dstPath);
|
||||
} else if(srcStats.isDirectory()) {
|
||||
@@ -83,7 +82,7 @@ exports.copyFile = function(srcPath,dstPath) {
|
||||
dstFile = fs.openSync(dstPath,"w"),
|
||||
bytesRead = 1,
|
||||
pos = 0;
|
||||
while (bytesRead > 0) {
|
||||
while(bytesRead > 0) {
|
||||
bytesRead = fs.readSync(srcFile,fileBuffer,0,FILE_BUFFER_LENGTH,pos);
|
||||
fs.writeSync(dstFile,fileBuffer,0,bytesRead);
|
||||
pos += bytesRead;
|
||||
@@ -148,7 +147,7 @@ exports.deleteDirectory = function(dirPath) {
|
||||
fs.unlinkSync(currPath);
|
||||
}
|
||||
}
|
||||
fs.rmdirSync(dirPath);
|
||||
fs.rmdirSync(dirPath);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -239,6 +238,10 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
// Save as a .tid file
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else if($tw.Wiki.tiddlerSerializerModules && $tw.Wiki.tiddlerSerializerModules[tiddlerType]) {
|
||||
// A serializer is registered for this content type - save as a single self-contained file
|
||||
fileInfo.type = tiddlerType;
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else {
|
||||
// Save as a text/binary file and a .meta file
|
||||
fileInfo.type = tiddlerType;
|
||||
@@ -255,7 +258,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
// Overriding to the .tid extension needs special handling
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else if (metaExt === ".json") {
|
||||
} else if(metaExt === ".json") {
|
||||
// Overriding to the .json extension needs special handling
|
||||
fileInfo.type = "application/json";
|
||||
fileInfo.hasMetaFile = false;
|
||||
@@ -345,18 +348,18 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
// Replace any Windows control codes
|
||||
filepath = filepath.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
|
||||
// Replace any leading spaces with the same number of underscores
|
||||
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_")});
|
||||
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_");});
|
||||
//If the path does not start with "." or ".." && a path seperator, then
|
||||
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
|
||||
// Don't let the filename start with any dots because such files are invisible on *nix
|
||||
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_")});
|
||||
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_");});
|
||||
}
|
||||
// Replace any Unicode control codes
|
||||
filepath = filepath.replace(/[\x00-\x1f\x80-\x9f]/g,"_");
|
||||
// Replace any characters that can't be used in cross-platform filenames
|
||||
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
|
||||
// Replace any dots or spaces at the end of the extension with the same number of underscores
|
||||
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_")});
|
||||
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_");});
|
||||
// Truncate the extension if it is too long
|
||||
if(extension.length > 32) {
|
||||
extension = extension.substr(0,32);
|
||||
@@ -382,9 +385,9 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
}
|
||||
// Add a uniquifier if the file already exists (default)
|
||||
var fullPath = path.resolve(directory, filepath + extension);
|
||||
if (!overwrite) {
|
||||
if(!overwrite) {
|
||||
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
|
||||
count = 0;
|
||||
count = 0;
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
if(oldPath && oldPath == fullPath) break;
|
||||
@@ -401,7 +404,7 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
writePath.indexOf(path.resolve(directory)) == 0 ||
|
||||
writePath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
|
||||
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
|
||||
}
|
||||
}
|
||||
if(encode) {
|
||||
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath));
|
||||
}
|
||||
@@ -417,7 +420,16 @@ Save a tiddler to a file described by the fileInfo:
|
||||
*/
|
||||
exports.saveTiddlerToFile = function(tiddler,fileInfo,callback) {
|
||||
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
|
||||
if(fileInfo.hasMetaFile) {
|
||||
var serializer = $tw.Wiki.tiddlerSerializerModules && $tw.Wiki.tiddlerSerializerModules[fileInfo.type];
|
||||
if(serializer && !fileInfo.hasMetaFile && fileInfo.type !== "application/x-tiddler" && fileInfo.type !== "application/json") {
|
||||
var typeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {encoding: "utf8"};
|
||||
fs.writeFile(fileInfo.filepath,serializer(tiddler),typeInfo.encoding,function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null,fileInfo);
|
||||
});
|
||||
} else if(fileInfo.hasMetaFile) {
|
||||
// Save the tiddler as a separate body and meta file
|
||||
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
|
||||
fs.writeFile(fileInfo.filepath,tiddler.fields.text || "",typeInfo.encoding,function(err) {
|
||||
@@ -459,7 +471,11 @@ Save a tiddler to a file described by the fileInfo:
|
||||
*/
|
||||
exports.saveTiddlerToFileSync = function(tiddler,fileInfo) {
|
||||
$tw.utils.createDirectory(path.dirname(fileInfo.filepath));
|
||||
if(fileInfo.hasMetaFile) {
|
||||
var serializer = $tw.Wiki.tiddlerSerializerModules && $tw.Wiki.tiddlerSerializerModules[fileInfo.type];
|
||||
if(serializer && !fileInfo.hasMetaFile && fileInfo.type !== "application/x-tiddler" && fileInfo.type !== "application/json") {
|
||||
var typeInfo = $tw.config.contentTypeInfo[fileInfo.type] || {encoding: "utf8"};
|
||||
fs.writeFileSync(fileInfo.filepath,serializer(tiddler),typeInfo.encoding);
|
||||
} else if(fileInfo.hasMetaFile) {
|
||||
// Save the tiddler as a separate body and meta file
|
||||
var typeInfo = $tw.config.contentTypeInfo[tiddler.fields.type || "text/plain"] || {encoding: "utf8"};
|
||||
fs.writeFileSync(fileInfo.filepath,tiddler.fields.text || "",typeInfo.encoding);
|
||||
@@ -521,12 +537,12 @@ Cleanup old files on disk, by comparing the options values:
|
||||
*/
|
||||
exports.cleanupTiddlerFiles = function(options,callback) {
|
||||
var adaptorInfo = options.adaptorInfo || {},
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
|
||||
$tw.utils.deleteTiddlerFile(adaptorInfo,function(err) {
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
if((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
// Error deleting the previous file on disk, should fail gracefully
|
||||
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: \""+title+"\"",err);
|
||||
return callback(null,bootInfo);
|
||||
|
||||
@@ -10,9 +10,7 @@ Authenticator for WWW basic authentication
|
||||
"use strict";
|
||||
|
||||
if($tw.node) {
|
||||
var util = require("util"),
|
||||
fs = require("fs"),
|
||||
url = require("url"),
|
||||
var fs = require("fs"),
|
||||
path = require("path");
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ exports.info = {
|
||||
exports.handler = function(request,response,state) {
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||
responseHeaders = {
|
||||
"Content-Type": state.server.get("root-serve-type")
|
||||
};
|
||||
"Content-Type": state.server.get("root-serve-type")
|
||||
};
|
||||
state.sendResponse(200,responseHeaders,text);
|
||||
};
|
||||
|
||||
@@ -33,8 +33,8 @@ exports.handler = function(request,response,state) {
|
||||
}
|
||||
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
|
||||
|
||||
// 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,{},text,"utf8");
|
||||
var headers = {"Content-Type": renderType};
|
||||
state.sendResponse(200,headers,text,"utf8");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
|
||||
@@ -18,7 +18,7 @@ exports.info = {
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
fields = $tw.utils.parseJSONSafe(state.data);
|
||||
fields = $tw.utils.parseJSONSafe(state.data);
|
||||
// Pull up any subfields in the `fields` object
|
||||
if(fields.fields) {
|
||||
$tw.utils.each(fields.fields,function(field,name) {
|
||||
|
||||
@@ -9,14 +9,15 @@ Serve tiddlers over http
|
||||
|
||||
"use strict";
|
||||
|
||||
let fs, url, path, querystring, crypto, zlib;
|
||||
|
||||
if($tw.node) {
|
||||
var util = require("util"),
|
||||
fs = require("fs"),
|
||||
url = require("url"),
|
||||
path = require("path"),
|
||||
querystring = require("querystring"),
|
||||
crypto = require("crypto"),
|
||||
zlib = require("zlib");
|
||||
fs = require("fs"),
|
||||
url = require("url"),
|
||||
path = require("path"),
|
||||
querystring = require("querystring"),
|
||||
crypto = require("crypto"),
|
||||
zlib = require("zlib");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -41,7 +42,9 @@ function Server(options) {
|
||||
}
|
||||
}
|
||||
// Setup the default required plugins
|
||||
this.requiredPlugins = this.get("required-plugins").split(',');
|
||||
this.requiredPlugins = this.get("required-plugins").split(",");
|
||||
// Initialise CORS
|
||||
this.corsEnable = this.get("cors-enable") === "yes";
|
||||
// Initialise CSRF
|
||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||
// Initialize Gzip compression
|
||||
@@ -60,9 +63,9 @@ function Server(options) {
|
||||
this.authorizationPrincipals = {
|
||||
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
||||
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
||||
}
|
||||
};
|
||||
if(this.get("admin") || authorizedUserName !== "(anon)") {
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(",").map($tw.utils.trim);
|
||||
}
|
||||
// Load and initialise authenticators
|
||||
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
||||
@@ -89,7 +92,7 @@ function Server(options) {
|
||||
this.listenOptions = {
|
||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
|
||||
passphrase: tlsPassphrase || ''
|
||||
passphrase: tlsPassphrase || ""
|
||||
};
|
||||
this.protocol = "https";
|
||||
}
|
||||
@@ -114,7 +117,7 @@ encoding: the encoding of the data to send (passed to the end method of the resp
|
||||
*/
|
||||
function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||
if(this.enableBrowserCache && (statusCode == 200)) {
|
||||
var hash = crypto.createHash('md5');
|
||||
var hash = crypto.createHash("md5");
|
||||
// Put everything into the hash that could change and invalidate the data that
|
||||
// the browser already stored. The headers the data and the encoding.
|
||||
hash.update(data);
|
||||
@@ -209,7 +212,6 @@ Server.prototype.addAuthenticator = function(AuthenticatorClass) {
|
||||
Server.prototype.findMatchingRoute = function(request,state) {
|
||||
for(var t=0; t<this.routes.length; t++) {
|
||||
var potentialRoute = this.routes[t],
|
||||
pathRegExp = potentialRoute.path,
|
||||
pathname = state.urlInfo.pathname,
|
||||
match;
|
||||
if(state.pathPrefix) {
|
||||
@@ -248,7 +250,7 @@ Check whether a given user is authorized for the specified authorizationType ("r
|
||||
Server.prototype.isAuthorized = function(authorizationType,username) {
|
||||
var principals = this.authorizationPrincipals[authorizationType] || [];
|
||||
return principals.indexOf("(anon)") !== -1 || (username && (principals.indexOf("(authenticated)") !== -1 || principals.indexOf(username) !== -1));
|
||||
}
|
||||
};
|
||||
|
||||
Server.prototype.requestHandler = function(request,response,options) {
|
||||
options = options || {};
|
||||
@@ -261,6 +263,13 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
state.urlInfo = url.parse(request.url);
|
||||
state.queryParameters = querystring.parse(state.urlInfo.query);
|
||||
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);
|
||||
// Get the principals authorized to access this resource
|
||||
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
||||
@@ -285,6 +294,12 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Reply to OPTIONS
|
||||
if(this.corsEnable && request.method === "OPTIONS") {
|
||||
response.writeHead(204);
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
// Find the route that matches this path
|
||||
var route = self.findMatchingRoute(request,state);
|
||||
// Optionally output debug info
|
||||
@@ -322,7 +337,7 @@ Server.prototype.requestHandler = function(request,response,options) {
|
||||
request.on("end",function() {
|
||||
state.data = Buffer.concat(data);
|
||||
route.handler(request,response,state);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
response.writeHead(400,"Invalid bodyFormat " + route.bodyFormat + " in route " + route.method + " " + route.path.source);
|
||||
response.end();
|
||||
@@ -347,8 +362,8 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
}
|
||||
// Warn if required plugins are missing
|
||||
var missing = [];
|
||||
for (var index=0; index<this.requiredPlugins.length; index++) {
|
||||
if (!this.wiki.getTiddler(this.requiredPlugins[index])) {
|
||||
for(var index=0; index<this.requiredPlugins.length; index++) {
|
||||
if(!this.wiki.getTiddler(this.requiredPlugins[index])) {
|
||||
missing.push(this.requiredPlugins[index]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,22 +9,22 @@ Base64 UTF-8 utlity functions.
|
||||
|
||||
"use strict";
|
||||
|
||||
const{ TextEncoder, TextDecoder } = require("node:util");
|
||||
const { TextEncoder, TextDecoder } = require("node:util");
|
||||
|
||||
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
|
||||
exports.btoa = (binstr) => Buffer.from(binstr, "binary").toString("base64");
|
||||
|
||||
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
|
||||
exports.atob = (b64) => Buffer.from(b64, "base64").toString("binary");
|
||||
|
||||
function base64ToBytes(base64) {
|
||||
const binString = exports.atob(base64);
|
||||
return Uint8Array.from(binString, m => m.codePointAt(0));
|
||||
return Uint8Array.from(binString, (m) => m.codePointAt(0));
|
||||
};
|
||||
|
||||
function bytesToBase64(bytes) {
|
||||
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
|
||||
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
|
||||
return exports.btoa(binString);
|
||||
};
|
||||
|
||||
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
|
||||
exports.base64EncodeUtf8 = (str) => bytesToBase64(new TextEncoder().encode(str));
|
||||
|
||||
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));
|
||||
exports.base64DecodeUtf8 = (str) => new TextDecoder().decode(base64ToBytes(str));
|
||||
|
||||
@@ -16,8 +16,7 @@ ignoreEnvironmentVariables: defaults to false
|
||||
*/
|
||||
exports.getAllPlugins = function(options) {
|
||||
options = options || {};
|
||||
var fs = require("fs"),
|
||||
path = require("path"),
|
||||
var path = require("path"),
|
||||
tiddlers = {};
|
||||
// Collect up the library plugins
|
||||
var collectPlugins = function(folder) {
|
||||
|
||||
@@ -6,6 +6,7 @@ Appearance/Caption: Appearance
|
||||
Appearance/Hint: Ways to customise the appearance of your TiddlyWiki.
|
||||
Basics/AnimDuration/Prompt: Animation duration
|
||||
Basics/AutoFocus/Prompt: Default focus field for new tiddlers
|
||||
Basics/AutoFocusEdit/Prompt: Default focus field for existing tiddlers
|
||||
Basics/Caption: Basics
|
||||
Basics/DefaultTiddlers/BottomHint: Use [[double square brackets]] for titles with spaces. Or you can choose to {{retain story ordering||$:/snippets/retain-story-ordering-button}}
|
||||
Basics/DefaultTiddlers/Prompt: Default tiddlers
|
||||
|
||||
4
core/language/en-GB/Draft.multids
Normal file
4
core/language/en-GB/Draft.multids
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/language/Draft/
|
||||
|
||||
Attribution: Draft of '<<draft-title>>' by {{$:/status/UserName}}
|
||||
Title: Draft of '<<draft-title>>'
|
||||
@@ -15,6 +15,8 @@ Listing/Preview/TextRaw: Text (Raw)
|
||||
Listing/Preview/Fields: Fields
|
||||
Listing/Preview/Diff: Diff
|
||||
Listing/Preview/DiffFields: Diff (Fields)
|
||||
Listing/ImportOptions/Caption: Import options
|
||||
Listing/ImportOptions/NoMatch: No import options apply to these files.
|
||||
Listing/Rename/Tooltip: Rename tiddler before importing
|
||||
Listing/Rename/Prompt: Rename to:
|
||||
Listing/Rename/ConfirmRename: Rename tiddler
|
||||
|
||||
@@ -9,6 +9,11 @@ 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/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/CascadeInfo/Heading: Cascade Details
|
||||
Advanced/CascadeInfo/Hint: These are the view template segments that are resolved for each of the system view template cascades
|
||||
Advanced/CascadeInfo/Detail/View: View
|
||||
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Active cascade filter
|
||||
Advanced/CascadeInfo/Detail/Template: Template
|
||||
Fields/Caption: Fields
|
||||
List/Caption: List
|
||||
List/Empty: This tiddler does not have a list
|
||||
|
||||
116
core/modules/background-actions.js
Normal file
116
core/modules/background-actions.js
Normal file
@@ -0,0 +1,116 @@
|
||||
/*\
|
||||
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;
|
||||
@@ -197,7 +197,7 @@ FramedEngine.prototype.handleFocusEvent = function(event) {
|
||||
Handle a keydown event
|
||||
*/
|
||||
FramedEngine.prototype.handleKeydownEvent = function(event) {
|
||||
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||
if($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,19 +48,19 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.toolbarNode = this.document.createElement("div");
|
||||
this.toolbarNode.className = "tc-editor-toolbar";
|
||||
parent.insertBefore(this.toolbarNode,nextSibling);
|
||||
this.renderChildren(this.toolbarNode,null);
|
||||
this.domNodes.push(this.toolbarNode);
|
||||
this.renderChildren(this.toolbarNode,null);
|
||||
}
|
||||
// Create our element
|
||||
var editInfo = this.getEditInfo(),
|
||||
Engine = this.editShowToolbar ? toolbarEngine : nonToolbarEngine;
|
||||
this.engine = new Engine({
|
||||
widget: this,
|
||||
value: editInfo.value,
|
||||
type: editInfo.type,
|
||||
parentNode: parent,
|
||||
nextSibling: nextSibling
|
||||
});
|
||||
widget: this,
|
||||
value: editInfo.value,
|
||||
type: editInfo.type,
|
||||
parentNode: parent,
|
||||
nextSibling: nextSibling
|
||||
});
|
||||
// Call the postRender hook
|
||||
if(this.postRender) {
|
||||
this.postRender();
|
||||
@@ -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) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
} else if (changedTiddlers[this.editRefreshTitle]) {
|
||||
} else if(changedTiddlers[this.editRefreshTitle]) {
|
||||
this.engine.updateDomNodeText(this.getEditInfo().value);
|
||||
} else if(changedTiddlers[this.editTitle]) {
|
||||
var editInfo = this.getEditInfo();
|
||||
@@ -274,8 +274,8 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
});
|
||||
if($tw.keyboardManager.checkKeyDescriptors(event,keyInfoArray)) {
|
||||
var clickEvent = this.document.createEvent("Events");
|
||||
clickEvent.initEvent("click",true,false);
|
||||
el.dispatchEvent(clickEvent);
|
||||
clickEvent.initEvent("click",true,false);
|
||||
el.dispatchEvent(clickEvent);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
|
||||
@@ -10,7 +10,7 @@ Text editor operation to excise the selection to a new tiddler
|
||||
"use strict";
|
||||
|
||||
function isMarkdown(mediaType) {
|
||||
return mediaType === 'text/markdown' || mediaType === 'text/x-markdown';
|
||||
return mediaType === "text/markdown" || mediaType === "text/x-markdown";
|
||||
}
|
||||
|
||||
exports["excise"] = function(event,operation) {
|
||||
|
||||
@@ -19,7 +19,7 @@ exports["wrap-lines"] = function(event,operation) {
|
||||
operation.cutStart = operation.selStart - (prefix.length + 1);
|
||||
operation.cutEnd = operation.selEnd + suffix.length + 1;
|
||||
// Also cut the following newline (if there is any)
|
||||
if (operation.text[operation.cutEnd] === "\n") {
|
||||
if(operation.text[operation.cutEnd] === "\n") {
|
||||
operation.cutEnd++;
|
||||
}
|
||||
// Replace with selection
|
||||
|
||||
@@ -44,7 +44,7 @@ exports["wrap-selection"] = function(event,operation) {
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function togglePrefixSuffix() {
|
||||
if(o.text.substring(o.selStart - prefix.length, o.selStart + suffix.length) === prefix + suffix) {
|
||||
|
||||
106
core/modules/filter-tracker.js
Normal file
106
core/modules/filter-tracker.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/*\
|
||||
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;
|
||||
@@ -24,7 +24,7 @@ exports.cascade = function(operationSubFunction,options) {
|
||||
}
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler","")
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
|
||||
}));
|
||||
if(output.length !== 0) {
|
||||
result = output[0];
|
||||
@@ -34,5 +34,5 @@ exports.cascade = function(operationSubFunction,options) {
|
||||
results.push(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ exports.filter = function(operationSubFunction,options) {
|
||||
results.each(function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
@@ -30,5 +30,5 @@ exports.filter = function(operationSubFunction,options) {
|
||||
});
|
||||
results.remove(resultsToRemove);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -7,8 +7,6 @@ Assign a value to a variable
|
||||
|
||||
\*/
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.map = function(operationSubFunction,options) {
|
||||
$tw.utils.each(inputTitles,function(title) {
|
||||
var filtered = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
@@ -28,12 +28,12 @@ exports.map = function(operationSubFunction,options) {
|
||||
if(filtered.length && flatten) {
|
||||
$tw.utils.each(filtered,function(value) {
|
||||
results.push(value);
|
||||
})
|
||||
});
|
||||
} else {
|
||||
results.push(filtered[0]||"");
|
||||
}
|
||||
++index;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ exports.reduce = function(operationSubFunction,options) {
|
||||
results.each(function(title) {
|
||||
var list = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""}),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
@@ -31,5 +31,5 @@ exports.reduce = function(operationSubFunction,options) {
|
||||
results.clear();
|
||||
results.push(accumulator);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ exports.sort = function(operationSubFunction,options) {
|
||||
results.each(function(title) {
|
||||
var key = operationSubFunction(options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
|
||||
}));
|
||||
sortKeys.push(key[0] || "");
|
||||
});
|
||||
@@ -36,12 +36,12 @@ exports.sort = function(operationSubFunction,options) {
|
||||
// Sort the indexes
|
||||
compareFn = $tw.utils.makeCompareFunction(sortType,{defaultType: "string", invert:invert, isCaseSensitive:isCaseSensitive});
|
||||
indexes = indexes.sort(function(a,b) {
|
||||
return compareFn(sortKeys[a],sortKeys[b]);
|
||||
return compareFn(sortKeys[a],sortKeys[b]);
|
||||
});
|
||||
// Add to results in correct order
|
||||
$tw.utils.each(indexes,function(index) {
|
||||
results.push(inputTitles[index]);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -43,7 +43,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
var bracket = filterString.charAt(nextBracketPos);
|
||||
operator.operator = filterString.substring(p,nextBracketPos);
|
||||
// Any suffix?
|
||||
var colon = operator.operator.indexOf(':');
|
||||
var colon = operator.operator.indexOf(":");
|
||||
if(colon > -1) {
|
||||
// The raw suffix for older filters
|
||||
operator.suffix = operator.operator.substring(colon + 1);
|
||||
@@ -67,7 +67,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
operator.operands = [];
|
||||
var parseOperand = function(bracketType) {
|
||||
var operand = {};
|
||||
switch (bracketType) {
|
||||
switch(bracketType) {
|
||||
case "{": // Curly brackets
|
||||
operand.indirect = true;
|
||||
nextBracketPos = filterString.indexOf("}",p);
|
||||
@@ -108,7 +108,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
}
|
||||
operator.operands.push(operand);
|
||||
p = nextBracketPos + 1;
|
||||
}
|
||||
};
|
||||
|
||||
p = nextBracketPos + 1;
|
||||
parseOperand(bracket);
|
||||
@@ -228,16 +228,11 @@ exports.getFilterRunPrefixes = function() {
|
||||
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
|
||||
}
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
};
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
try {
|
||||
const fnResult = fn.call(this,source,widget);
|
||||
return fnResult;
|
||||
} catch(e) {
|
||||
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
|
||||
}
|
||||
return fn.call(this,source,widget);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -32,4 +32,4 @@ var modes = {
|
||||
"gt": function(value) {return value > 0;},
|
||||
"lteq": function(value) {return value <= 0;},
|
||||
"lt": function(value) {return value < 0;}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,4 +31,4 @@ exports["deserialize"] = function(source,operator,options) {
|
||||
return [$tw.language.getString("Error/DeserializeOperator/MissingOperand")];
|
||||
}
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,8 +15,8 @@ Export our filter function
|
||||
*/
|
||||
exports.each = function(source,operator,options) {
|
||||
var results =[] ,
|
||||
value,values = {},
|
||||
field = operator.operand || "title";
|
||||
value,values = {},
|
||||
field = operator.operand || "title";
|
||||
if(operator.suffix === "value" && field === "title") {
|
||||
source(function(tiddler,title) {
|
||||
if(!$tw.utils.hop(values,title)) {
|
||||
|
||||
@@ -53,7 +53,7 @@ exports.field = function(source,operator,options) {
|
||||
if(source.byField && operator.operand) {
|
||||
indexedResults = source.byField(fieldname,operator.operand);
|
||||
if(indexedResults) {
|
||||
return indexedResults
|
||||
return indexedResults;
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -24,7 +24,7 @@ exports.fields = function(source,operator,options) {
|
||||
for(fieldName in tiddler.fields) {
|
||||
(operand.indexOf(fieldName) !== -1) ? $tw.utils.pushTop(results,fieldName) : "";
|
||||
}
|
||||
} else if (suffixes.indexOf("exclude") !== -1) {
|
||||
} else if(suffixes.indexOf("exclude") !== -1) {
|
||||
for(fieldName in tiddler.fields) {
|
||||
(operand.indexOf(fieldName) !== -1) ? "" : $tw.utils.pushTop(results,fieldName);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ exports.filter = function(source,operator,options) {
|
||||
source(function(tiddler,title) {
|
||||
var list = filterFn.call(options.wiki,options.wiki.makeTiddlerIterator([title]),options.widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": options.widget.getVariable("currentTiddler","")
|
||||
"..currentTiddler": options.widget.getVariable("currentTiddler",{defaultValue:""})
|
||||
}));
|
||||
if((list.length > 0) === target) {
|
||||
results.push(title);
|
||||
|
||||
@@ -12,7 +12,7 @@ Export our filter function
|
||||
exports.timestamp = function(source,operand,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
if (title.match(/^-?\d+$/)) {
|
||||
if(title.match(/^-?\d+$/)) {
|
||||
var value = new Date(Number(title));
|
||||
results.push($tw.utils.formatDateString(value,operand || "[UTC]YYYY0MM0DD0hh0mm0ss0XXX"));
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ returns the value at a given index of datatiddlers
|
||||
Export our filter function
|
||||
*/
|
||||
exports.getindex = function(source,operator,options) {
|
||||
var data,title,results = [];
|
||||
var data,results = [];
|
||||
if(operator.operand){
|
||||
source(function(tiddler,title) {
|
||||
title = tiddler ? tiddler.fields.title : title;
|
||||
|
||||
@@ -157,13 +157,13 @@ function convertDataItemValueToStrings(item) {
|
||||
if(item === undefined) {
|
||||
return undefined;
|
||||
} else if(item === null) {
|
||||
return ["null"]
|
||||
return ["null"];
|
||||
} else if(typeof item === "object") {
|
||||
var results = [],i,t;
|
||||
if(Array.isArray(item)) {
|
||||
// Return all the items in arrays recursively
|
||||
for(i=0; i<item.length; i++) {
|
||||
t = convertDataItemValueToStrings(item[i])
|
||||
t = convertDataItemValueToStrings(item[i]);
|
||||
if(t !== undefined) {
|
||||
results.push.apply(results,t);
|
||||
}
|
||||
@@ -231,7 +231,7 @@ function getItemAtIndex(item,index) {
|
||||
return item[index];
|
||||
} else if(Array.isArray(item)) {
|
||||
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
|
||||
} else {
|
||||
return undefined;
|
||||
@@ -289,7 +289,7 @@ function setDataItem(data,indexes,value) {
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current)) {
|
||||
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
|
||||
if(typeof current === "object") {
|
||||
@@ -316,7 +316,7 @@ function deleteDataItem(data,indexes) {
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current) && current !== null) {
|
||||
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
|
||||
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||
current.splice(lastIndex,1);
|
||||
|
||||
@@ -25,7 +25,7 @@ exports.lookup = function(source,operator,options) {
|
||||
indexSuffix = (suffixes[1] && suffixes[1][0] === "index") ? true : false,
|
||||
target;
|
||||
if(operator.operands.length == 2) {
|
||||
target = operator.operands[1]
|
||||
target = operator.operands[1];
|
||||
} else {
|
||||
target = indexSuffix ? "0": "text";
|
||||
}
|
||||
|
||||
@@ -17,35 +17,35 @@ Note that strings are converted to numbers automatically. Trailing non-digits ar
|
||||
"use strict";
|
||||
|
||||
exports.negate = makeNumericBinaryOperator(
|
||||
function(a) {return -a}
|
||||
function(a) {return -a;}
|
||||
);
|
||||
|
||||
exports.abs = makeNumericBinaryOperator(
|
||||
function(a) {return Math.abs(a)}
|
||||
function(a) {return Math.abs(a);}
|
||||
);
|
||||
|
||||
exports.ceil = makeNumericBinaryOperator(
|
||||
function(a) {return Math.ceil(a)}
|
||||
function(a) {return Math.ceil(a);}
|
||||
);
|
||||
|
||||
exports.floor = makeNumericBinaryOperator(
|
||||
function(a) {return Math.floor(a)}
|
||||
function(a) {return Math.floor(a);}
|
||||
);
|
||||
|
||||
exports.round = makeNumericBinaryOperator(
|
||||
function(a) {return Math.round(a)}
|
||||
function(a) {return Math.round(a);}
|
||||
);
|
||||
|
||||
exports.trunc = makeNumericBinaryOperator(
|
||||
function(a) {return Math.trunc(a)}
|
||||
function(a) {return Math.trunc(a);}
|
||||
);
|
||||
|
||||
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(
|
||||
function(a) {return Math.sign(a)}
|
||||
function(a) {return Math.sign(a);}
|
||||
);
|
||||
|
||||
exports.add = makeNumericBinaryOperator(
|
||||
@@ -103,29 +103,29 @@ exports.log = makeNumericBinaryOperator(
|
||||
);
|
||||
|
||||
exports.sum = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
function(accumulator,value) {return accumulator + value;},
|
||||
0 // Initial value
|
||||
);
|
||||
|
||||
exports.product = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator * value},
|
||||
function(accumulator,value) {return accumulator * value;},
|
||||
1 // Initial value
|
||||
);
|
||||
|
||||
exports.maxall = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return Math.max(accumulator,value)},
|
||||
function(accumulator,value) {return Math.max(accumulator,value);},
|
||||
-Infinity // Initial value
|
||||
);
|
||||
|
||||
exports.minall = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return Math.min(accumulator,value)},
|
||||
function(accumulator,value) {return Math.min(accumulator,value);},
|
||||
Infinity // Initial value
|
||||
);
|
||||
|
||||
exports.median = makeNumericArrayOperator(
|
||||
function(values) {
|
||||
var len = values.length, median;
|
||||
values.sort(function(a,b) {return a-b});
|
||||
values.sort(function(a,b) {return a-b;});
|
||||
if(len % 2) {
|
||||
// Odd, return the middle number
|
||||
median = values[(len - 1) / 2];
|
||||
@@ -138,7 +138,7 @@ exports.median = makeNumericArrayOperator(
|
||||
);
|
||||
|
||||
exports.average = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
function(accumulator,value) {return accumulator + value;},
|
||||
0, // Initial value
|
||||
function(finalValue,numberOfValues) {
|
||||
return finalValue/numberOfValues;
|
||||
@@ -146,7 +146,7 @@ exports.average = makeNumericReducingOperator(
|
||||
);
|
||||
|
||||
exports.variance = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
function(accumulator,value) {return accumulator + value;},
|
||||
0,
|
||||
function(finalValue,numberOfValues,originalValues) {
|
||||
return getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||
@@ -154,7 +154,7 @@ exports.variance = makeNumericReducingOperator(
|
||||
);
|
||||
|
||||
exports["standard-deviation"] = makeNumericReducingOperator(
|
||||
function(accumulator,value) {return accumulator + value},
|
||||
function(accumulator,value) {return accumulator + value;},
|
||||
0,
|
||||
function(finalValue,numberOfValues,originalValues) {
|
||||
var variance = getVarianceFromArray(originalValues,finalValue/numberOfValues);
|
||||
@@ -164,31 +164,31 @@ exports["standard-deviation"] = makeNumericReducingOperator(
|
||||
|
||||
//trigonometry
|
||||
exports.cos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.cos(a)}
|
||||
function(a) {return Math.cos(a);}
|
||||
);
|
||||
|
||||
exports.sin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.sin(a)}
|
||||
function(a) {return Math.sin(a);}
|
||||
);
|
||||
|
||||
exports.tan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.tan(a)}
|
||||
function(a) {return Math.tan(a);}
|
||||
);
|
||||
|
||||
exports.acos = makeNumericBinaryOperator(
|
||||
function(a) {return Math.acos(a)}
|
||||
function(a) {return Math.acos(a);}
|
||||
);
|
||||
|
||||
exports.asin = makeNumericBinaryOperator(
|
||||
function(a) {return Math.asin(a)}
|
||||
function(a) {return Math.asin(a);}
|
||||
);
|
||||
|
||||
exports.atan = makeNumericBinaryOperator(
|
||||
function(a) {return Math.atan(a)}
|
||||
function(a) {return Math.atan(a);}
|
||||
);
|
||||
|
||||
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
|
||||
@@ -222,8 +222,8 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||
return [];
|
||||
}
|
||||
var value = result.reduce(function(accumulator,currentValue) {
|
||||
return fnCalc(accumulator,currentValue);
|
||||
},initialValue);
|
||||
return fnCalc(accumulator,currentValue);
|
||||
},initialValue);
|
||||
if(fnFinal) {
|
||||
value = fnFinal(value,result.length,result);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.range = function(source,operator,options) {
|
||||
}
|
||||
// Process the parts
|
||||
var beg, end, inc, i, fixed = 0;
|
||||
for (i=0; i<parts.length; i++) {
|
||||
for(i=0; i<parts.length; i++) {
|
||||
// Validate real number
|
||||
if(!/^\s*[+-]?((\d+(\.\d*)?)|(\.\d+))\s*$/.test(parts[i])) {
|
||||
return ["range: bad number \"" + parts[i] + "\""];
|
||||
@@ -36,10 +36,10 @@ exports.range = function(source,operator,options) {
|
||||
switch(parts.length) {
|
||||
case 1:
|
||||
end = parts[0];
|
||||
if (end >= 1) {
|
||||
if(end >= 1) {
|
||||
beg = 1;
|
||||
}
|
||||
else if (end <= -1) {
|
||||
else if(end <= -1) {
|
||||
beg = -1;
|
||||
}
|
||||
else {
|
||||
@@ -72,7 +72,7 @@ exports.range = function(source,operator,options) {
|
||||
end += direction * 0.5 * Math.pow(0.1,fixed);
|
||||
var safety = 10010;
|
||||
// Enumerate the range
|
||||
if (end<beg) {
|
||||
if(end<beg) {
|
||||
for(i=beg; i>end; i+=inc) {
|
||||
results.push(i.toFixed(fixed));
|
||||
if(--safety<0) {
|
||||
|
||||
@@ -15,7 +15,7 @@ Export our filter function
|
||||
exports.removesuffix = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = (operator.suffixes || [])[0] || [];
|
||||
if (!operator.operand) {
|
||||
if(!operator.operand) {
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
|
||||
@@ -14,31 +14,31 @@ Export our filter function
|
||||
*/
|
||||
exports.sort = function(source,operator,options) {
|
||||
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;
|
||||
};
|
||||
|
||||
exports.nsort = function(source,operator,options) {
|
||||
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;
|
||||
};
|
||||
|
||||
exports.sortan = function(source, operator, options) {
|
||||
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;
|
||||
};
|
||||
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
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;
|
||||
};
|
||||
|
||||
exports.nsortcs = function(source,operator,options) {
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Export our filter function
|
||||
exports.suffix = function(source,operator,options) {
|
||||
var results = [],
|
||||
suffixes = (operator.suffixes || [])[0] || [];
|
||||
if (!operator.operand) {
|
||||
if(!operator.operand) {
|
||||
source(function(tiddler,title) {
|
||||
results.push(title);
|
||||
});
|
||||
|
||||
@@ -24,4 +24,4 @@ exports.variables = function(source,operator,options) {
|
||||
}
|
||||
}
|
||||
return names.sort();
|
||||
};
|
||||
};
|
||||
@@ -7,224 +7,224 @@ Extended filter operators to manipulate the current list.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
/*
|
||||
Fetch titles from the current list
|
||||
*/
|
||||
var prepare_results = function (source) {
|
||||
var prepare_results = function (source) {
|
||||
var results = [];
|
||||
source(function (tiddler, title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
source(function (tiddler, title) {
|
||||
results.push(title);
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Moves a number of items from the tail of the current list before the item named in the operand
|
||||
*/
|
||||
exports.putbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index, -count));
|
||||
};
|
||||
exports.putbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
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
|
||||
*/
|
||||
exports.putafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
results.slice(0, index + 1).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
exports.putafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -1) :
|
||||
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
|
||||
*/
|
||||
exports.replace = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -count) :
|
||||
results.slice(0, index).concat(results.slice(-count)).concat(results.slice(index + 1, -count));
|
||||
};
|
||||
exports.replace = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return (index === -1) ?
|
||||
results.slice(0, -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
|
||||
*/
|
||||
exports.putfirst = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(-count).concat(results.slice(0, -count));
|
||||
};
|
||||
exports.putfirst = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
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
|
||||
*/
|
||||
exports.putlast = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
return results.slice(count).concat(results.slice(0, count));
|
||||
};
|
||||
exports.putlast = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,1);
|
||||
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
|
||||
*/
|
||||
exports.move = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1),
|
||||
marker = results.splice(index, 1),
|
||||
offset = (index + count) > 0 ? index + count : 0;
|
||||
return results.slice(0, offset).concat(marker).concat(results.slice(offset));
|
||||
};
|
||||
exports.move = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand),
|
||||
count = $tw.utils.getInt(operator.suffix,1),
|
||||
marker = results.splice(index, 1),
|
||||
offset = (index + count) > 0 ? index + count : 0;
|
||||
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
|
||||
*/
|
||||
exports.allafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(index) :
|
||||
exports.allafter = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(index) :
|
||||
results.slice(index + 1);
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Returns the items from the current list that are before the item named in the operand
|
||||
*/
|
||||
exports.allbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(0, index + 1) :
|
||||
exports.allbefore = function (source, operator) {
|
||||
var results = prepare_results(source),
|
||||
index = results.indexOf(operator.operand);
|
||||
return (index === -1) ? [] :
|
||||
(operator.suffix) ? results.slice(0, index + 1) :
|
||||
results.slice(0, index);
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Appends the items listed in the operand array to the tail of the current list
|
||||
*/
|
||||
exports.append = function (source, operator) {
|
||||
var append = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || append.length;
|
||||
return (append.length === 0) ? results :
|
||||
(operator.prefix) ? results.concat(append.slice(-count)) :
|
||||
exports.append = function (source, operator) {
|
||||
var append = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || append.length;
|
||||
return (append.length === 0) ? results :
|
||||
(operator.prefix) ? results.concat(append.slice(-count)) :
|
||||
results.concat(append.slice(0, count));
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Prepends the items listed in the operand array to the head of the current list
|
||||
*/
|
||||
exports.prepend = function (source, operator) {
|
||||
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,prepend.length);
|
||||
return (prepend.length === 0) ? results :
|
||||
(operator.prefix) ? prepend.slice(-count).concat(results) :
|
||||
exports.prepend = function (source, operator) {
|
||||
var prepend = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = $tw.utils.getInt(operator.suffix,prepend.length);
|
||||
return (prepend.length === 0) ? results :
|
||||
(operator.prefix) ? prepend.slice(-count).concat(results) :
|
||||
prepend.slice(0, count).concat(results);
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Returns all items from the current list except the items listed in the operand array
|
||||
*/
|
||||
exports.remove = function (source, operator) {
|
||||
var array = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || array.length,
|
||||
p,
|
||||
len,
|
||||
index;
|
||||
len = array.length - 1;
|
||||
for (p = 0; p < count; ++p) {
|
||||
if (operator.prefix) {
|
||||
index = results.indexOf(array[len - p]);
|
||||
} else {
|
||||
index = results.indexOf(array[p]);
|
||||
}
|
||||
if (index !== -1) {
|
||||
results.splice(index, 1);
|
||||
}
|
||||
exports.remove = function (source, operator) {
|
||||
var array = $tw.utils.parseStringArray(operator.operand, "true"),
|
||||
results = prepare_results(source),
|
||||
count = parseInt(operator.suffix) || array.length,
|
||||
p,
|
||||
len,
|
||||
index;
|
||||
len = array.length - 1;
|
||||
for(p = 0; p < count; ++p) {
|
||||
if(operator.prefix) {
|
||||
index = results.indexOf(array[len - p]);
|
||||
} else {
|
||||
index = results.indexOf(array[p]);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
if(index !== -1) {
|
||||
results.splice(index, 1);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Returns all items from the current list sorted in the order of the items in the operand array
|
||||
*/
|
||||
exports.sortby = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
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);
|
||||
});
|
||||
exports.sortby = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Removes all duplicate items from the current list
|
||||
*/
|
||||
exports.unique = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
var set = results.reduce(function (a, b) {
|
||||
if (a.indexOf(b) < 0) {
|
||||
a.push(b);
|
||||
}
|
||||
return a;
|
||||
}, []);
|
||||
return set;
|
||||
};
|
||||
|
||||
var cycleValueInArray = function(results,operands,stepSize) {
|
||||
var resultsIndex,
|
||||
step = stepSize || 1,
|
||||
i = 0,
|
||||
opLength = operands.length,
|
||||
nextOperandIndex;
|
||||
for(i; i < opLength; i++) {
|
||||
resultsIndex = results.indexOf(operands[i]);
|
||||
if(resultsIndex !== -1) {
|
||||
break;
|
||||
}
|
||||
exports.unique = function (source, operator) {
|
||||
var results = prepare_results(source);
|
||||
var set = results.reduce(function (a, b) {
|
||||
if(a.indexOf(b) < 0) {
|
||||
a.push(b);
|
||||
}
|
||||
return a;
|
||||
}, []);
|
||||
return set;
|
||||
};
|
||||
|
||||
var cycleValueInArray = function(results,operands,stepSize) {
|
||||
var resultsIndex,
|
||||
step = stepSize || 1,
|
||||
i = 0,
|
||||
opLength = operands.length,
|
||||
nextOperandIndex;
|
||||
for(i; i < opLength; i++) {
|
||||
resultsIndex = results.indexOf(operands[i]);
|
||||
if(resultsIndex !== -1) {
|
||||
i = i + step;
|
||||
nextOperandIndex = (i < opLength ? i : i % opLength);
|
||||
if(operands.length > 1) {
|
||||
results.splice(resultsIndex,1,operands[nextOperandIndex]);
|
||||
} else {
|
||||
results.splice(resultsIndex,1);
|
||||
}
|
||||
} else {
|
||||
results.push(operands[0]);
|
||||
break;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
if(resultsIndex !== -1) {
|
||||
i = i + step;
|
||||
nextOperandIndex = (i < opLength ? i : i % opLength);
|
||||
if(operands.length > 1) {
|
||||
results.splice(resultsIndex,1,operands[nextOperandIndex]);
|
||||
} else {
|
||||
results.splice(resultsIndex,1);
|
||||
}
|
||||
} else {
|
||||
results.push(operands[0]);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
Toggles an item in the current list.
|
||||
*/
|
||||
exports.toggle = function(source,operator) {
|
||||
return cycleValueInArray(prepare_results(source),operator.operands);
|
||||
}
|
||||
exports.toggle = function(source,operator) {
|
||||
return cycleValueInArray(prepare_results(source),operator.operands);
|
||||
};
|
||||
|
||||
exports.cycle = function(source,operator) {
|
||||
var results = prepare_results(source),
|
||||
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
|
||||
step = $tw.utils.getInt(operator.operands[1]||"",1);
|
||||
if(step < 0) {
|
||||
operands.reverse();
|
||||
step = Math.abs(step);
|
||||
}
|
||||
return cycleValueInArray(results,operands,step);
|
||||
exports.cycle = function(source,operator) {
|
||||
var results = prepare_results(source),
|
||||
operands = (operator.operand.length ? $tw.utils.parseStringArray(operator.operand, "true") : [""]),
|
||||
step = $tw.utils.getInt(operator.operands[1]||"",1);
|
||||
if(step < 0) {
|
||||
operands.reverse();
|
||||
step = Math.abs(step);
|
||||
}
|
||||
return cycleValueInArray(results,operands,step);
|
||||
};
|
||||
|
||||
@@ -46,7 +46,7 @@ function BackSubIndexer(indexer,extractor) {
|
||||
BackSubIndexer.prototype.init = function() {
|
||||
// lazy init until first lookup
|
||||
this.index = null;
|
||||
}
|
||||
};
|
||||
|
||||
BackSubIndexer.prototype._init = function() {
|
||||
this.index = Object.create(null);
|
||||
@@ -60,11 +60,11 @@ BackSubIndexer.prototype._init = function() {
|
||||
self.index[target][sourceTitle] = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
BackSubIndexer.prototype.rebuild = function() {
|
||||
this.index = null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 [];
|
||||
}
|
||||
};
|
||||
|
||||
BackSubIndexer.prototype.update = function(updateDescriptor) {
|
||||
// lazy init/update until first lookup
|
||||
@@ -86,8 +86,8 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
|
||||
return;
|
||||
}
|
||||
var newTargets = [],
|
||||
oldTargets = [],
|
||||
self = this;
|
||||
oldTargets = [],
|
||||
self = this;
|
||||
if(updateDescriptor.old.exists) {
|
||||
oldTargets = this._getTarget(updateDescriptor.old.tiddler);
|
||||
}
|
||||
@@ -106,7 +106,7 @@ BackSubIndexer.prototype.update = function(updateDescriptor) {
|
||||
}
|
||||
self.index[target][updateDescriptor.new.tiddler.fields.title] = true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
BackSubIndexer.prototype.lookup = function(title) {
|
||||
if(!this.index) {
|
||||
@@ -117,6 +117,6 @@ BackSubIndexer.prototype.lookup = function(title) {
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.BackIndexer = BackIndexer;
|
||||
|
||||
@@ -19,7 +19,7 @@ FieldIndexer.prototype.init = function() {
|
||||
this.index = null;
|
||||
this.maxIndexedValueLength = DEFAULT_MAXIMUM_INDEXED_VALUE_LENGTH;
|
||||
this.addIndexMethods();
|
||||
}
|
||||
};
|
||||
|
||||
// Provided for testing
|
||||
FieldIndexer.prototype.setMaxIndexedValueLength = function(length) {
|
||||
@@ -33,14 +33,14 @@ FieldIndexer.prototype.addIndexMethods = function() {
|
||||
this.wiki.each.byField = function(name,value) {
|
||||
var lookup = self.lookup(name,value);
|
||||
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
|
||||
this.wiki.eachShadow.byField = function(name,value) {
|
||||
var lookup = self.lookup(name,value);
|
||||
return lookup && lookup.filter(function(title) {
|
||||
return self.wiki.isShadowTiddler(title)
|
||||
return self.wiki.isShadowTiddler(title);
|
||||
});
|
||||
};
|
||||
this.wiki.eachTiddlerPlusShadows.byField = function(name,value) {
|
||||
|
||||
@@ -14,12 +14,12 @@ exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||
this.updateCallback = updateCallback;
|
||||
this.resizeHandlers = new Map();
|
||||
this.dimensionsInfo = [
|
||||
["outer/width", win => win.outerWidth],
|
||||
["outer/height", win => win.outerHeight],
|
||||
["inner/width", win => win.innerWidth],
|
||||
["inner/height", win => win.innerHeight],
|
||||
["client/width", win => win.document.documentElement.clientWidth],
|
||||
["client/height", win => win.document.documentElement.clientHeight]
|
||||
["outer/width", (win) => win.outerWidth],
|
||||
["outer/height", (win) => win.outerHeight],
|
||||
["inner/width", (win) => win.innerWidth],
|
||||
["inner/height", (win) => win.innerHeight],
|
||||
["client/width", (win) => win.document.documentElement.clientWidth],
|
||||
["client/height", (win) => win.document.documentElement.clientHeight]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
67
core/modules/info/mediaquerytracker.js
Normal file
67
core/modules/info/mediaquerytracker.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/*\
|
||||
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 [];
|
||||
};
|
||||
@@ -33,13 +33,6 @@ exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||
// Screen size
|
||||
infoTiddlerFields.push({title: "$:/info/browser/screen/width", text: window.screen.width.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
|
||||
infoTiddlerFields.push({title: "$:/info/browser/language", text: navigator.language || ""});
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ function KeyboardManager(options) {
|
||||
this.shortcutParsedList = []; // Stores the parsed key descriptors
|
||||
this.shortcutPriorityList = []; // Stores the parsed shortcut priority
|
||||
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.isLinux ? "shortcuts-linux" : "shortcuts-not-linux");
|
||||
this.updateShortcutLists(this.getShortcutTiddlerList());
|
||||
@@ -161,7 +161,7 @@ KeyboardManager.prototype.getModifierKeys = function() {
|
||||
91, // Meta (left)
|
||||
93, // Meta (right)
|
||||
224 // Meta (Firefox)
|
||||
]
|
||||
];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -187,8 +187,7 @@ KeyboardManager.prototype.parseKeyDescriptor = function(keyDescriptor,options) {
|
||||
metaKey: false
|
||||
};
|
||||
for(var t=0; t<components.length; t++) {
|
||||
var s = components[t].toLowerCase(),
|
||||
c = s.charCodeAt(0);
|
||||
var s = components[t].toLowerCase();
|
||||
// Look for modifier keys
|
||||
if(s === "ctrl") {
|
||||
info.ctrlKey = true;
|
||||
@@ -266,7 +265,7 @@ KeyboardManager.prototype.getPrintableShortcuts = function(keyInfoArray) {
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
|
||||
return keyInfo &&
|
||||
@@ -293,15 +292,15 @@ KeyboardManager.prototype.getMatchingKeyDescriptor = function(event,keyInfoArray
|
||||
KeyboardManager.prototype.getEventModifierKeyDescriptor = function(event) {
|
||||
return event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey ? "ctrl" :
|
||||
event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey ? "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-shift" :
|
||||
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
|
||||
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-ctrl" :
|
||||
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.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-shift" :
|
||||
event.altKey && event.ctrlKey && !event.shiftKey && !event.metaKey ? "ctrl-alt" :
|
||||
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-ctrl" :
|
||||
event.metaKey && event.ctrlKey && event.shiftKey && !event.altKey ? "meta-ctrl-shift" :
|
||||
event.metaKey && event.ctrlKey && event.shiftKey && event.altKey ? "meta-ctrl-alt-shift" : "normal";
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.getShortcutTiddlerList = function() {
|
||||
@@ -371,8 +370,8 @@ KeyboardManager.prototype.handleShortcutChanges = function(changedTiddlers) {
|
||||
var newList = this.getShortcutTiddlerList();
|
||||
var hasChanged = $tw.utils.hopArray(changedTiddlers,this.shortcutTiddlers) ? true :
|
||||
($tw.utils.hopArray(changedTiddlers,newList) ? true :
|
||||
(this.detectNewShortcuts(changedTiddlers))
|
||||
);
|
||||
(this.detectNewShortcuts(changedTiddlers))
|
||||
);
|
||||
// Re-cache shortcuts if something changed
|
||||
if(hasChanged) {
|
||||
this.updateShortcutLists(newList);
|
||||
|
||||
@@ -24,8 +24,7 @@ exports.params = [
|
||||
Run the macro
|
||||
*/
|
||||
exports.run = function(filter,format) {
|
||||
var self = this,
|
||||
tiddlers = this.wiki.filterTiddlers(filter),
|
||||
var tiddlers = this.wiki.filterTiddlers(filter),
|
||||
tiddler,
|
||||
fields = [],
|
||||
t,f;
|
||||
@@ -46,24 +45,24 @@ exports.run = function(filter,format) {
|
||||
var p = fields.indexOf(value);
|
||||
if(p !== -1) {
|
||||
fields.splice(p,1);
|
||||
fields.unshift(value)
|
||||
fields.unshift(value);
|
||||
}
|
||||
});
|
||||
// Output the column headings
|
||||
var output = [], row = [];
|
||||
fields.forEach(function(value) {
|
||||
row.push(quoteAndEscape(value))
|
||||
row.push(quoteAndEscape(value));
|
||||
});
|
||||
output.push(row.join(","));
|
||||
// Output each tiddler
|
||||
for(var t=0;t<tiddlers.length; t++) {
|
||||
row = [];
|
||||
tiddler = this.wiki.getTiddler(tiddlers[t]);
|
||||
if(tiddler) {
|
||||
for(f=0; f<fields.length; f++) {
|
||||
row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : ""));
|
||||
}
|
||||
}
|
||||
if(tiddler) {
|
||||
for(f=0; f<fields.length; f++) {
|
||||
row.push(quoteAndEscape(tiddler ? tiddler.getFieldString(fields[f]) || "" : ""));
|
||||
}
|
||||
}
|
||||
output.push(row.join(","));
|
||||
}
|
||||
return output.join("\n");
|
||||
|
||||
@@ -31,8 +31,8 @@ exports.run = function(shortcuts,prefix,separator,suffix) {
|
||||
}));
|
||||
if(shortcutArray.length > 0) {
|
||||
shortcutArray.sort(function(a,b) {
|
||||
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||
})
|
||||
return a.toLowerCase().localeCompare(b.toLowerCase());
|
||||
});
|
||||
return prefix + shortcutArray.join(separator) + suffix;
|
||||
} else {
|
||||
return "";
|
||||
|
||||
@@ -7,19 +7,17 @@ The audio parser parses an audio tiddler into an embeddable HTML element
|
||||
|
||||
\*/
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var AudioParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "$audio", // Using $audio to enable widget interception
|
||||
attributes: {
|
||||
controls: {type: "string", value: "controls"},
|
||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||
}
|
||||
};
|
||||
type: "element",
|
||||
tag: "$audio", // Using $audio to enable widget interception
|
||||
attributes: {
|
||||
controls: {type: "string", value: "controls"},
|
||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||
}
|
||||
};
|
||||
|
||||
// Pass through source information
|
||||
if(options._canonical_uri) {
|
||||
|
||||
@@ -59,7 +59,7 @@ var BinaryParser = function(type,text,options) {
|
||||
class: {type: "string", value: "tc-binary-warning"}
|
||||
},
|
||||
children: [warn, link]
|
||||
}
|
||||
};
|
||||
this.tree = [element];
|
||||
this.source = text;
|
||||
this.type = type;
|
||||
|
||||
@@ -45,7 +45,7 @@ var CsvParser = function(type,text,options) {
|
||||
row.children.push({
|
||||
"type": "element", "tag": tag, "children": [{
|
||||
"type": "text",
|
||||
"text": columns[column] || ''
|
||||
"text": columns[column] || ""
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ exports.parseWhiteSpace = function(source,pos) {
|
||||
type: "whitespace",
|
||||
start: pos,
|
||||
end: p
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -107,13 +107,14 @@ exports.parseStringLiteral = function(source,pos) {
|
||||
type: "string",
|
||||
start: pos
|
||||
};
|
||||
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')/g;
|
||||
var reString = /(?:"""([\s\S]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/y;
|
||||
reString.lastIndex = pos;
|
||||
var match = reString.exec(source);
|
||||
if(match && match.index === pos) {
|
||||
node.value = match[1] !== undefined ? match[1] :(
|
||||
match[2] !== undefined ? match[2] : match[3]
|
||||
);
|
||||
match[2] !== undefined ? match[2] : (
|
||||
match[3] !== undefined ? match[3] : match[4]
|
||||
));
|
||||
node.end = pos + match[0].length;
|
||||
return node;
|
||||
} else {
|
||||
@@ -142,7 +143,14 @@ exports.parseParameterDefinition = function(paramString,options) {
|
||||
var paramInfo = {name: paramMatch[1]},
|
||||
defaultValue = paramMatch[2] || paramMatch[3] || paramMatch[4] || paramMatch[5];
|
||||
if(defaultValue !== undefined) {
|
||||
paramInfo["default"] = defaultValue;
|
||||
// Check for an MVV reference ((varname))
|
||||
var mvvDefaultMatch = /^\(\(([^)|]+)\)\)$/.exec(defaultValue);
|
||||
if(mvvDefaultMatch) {
|
||||
paramInfo.defaultType = "multivalue-variable";
|
||||
paramInfo.defaultVariable = mvvDefaultMatch[1];
|
||||
} else {
|
||||
paramInfo["default"] = defaultValue;
|
||||
}
|
||||
}
|
||||
params.push(paramInfo);
|
||||
// Look for the next parameter
|
||||
@@ -162,7 +170,7 @@ exports.parseMacroParameters = function(node,source,pos) {
|
||||
}
|
||||
node.end = pos;
|
||||
return node;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Look for a macro invocation parameter. Returns null if not found, or {type: "macro-parameter", name:, value:, start:, end:}
|
||||
@@ -173,7 +181,7 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
start: pos
|
||||
};
|
||||
// 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
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for the parameter
|
||||
@@ -184,16 +192,16 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
pos = token.end;
|
||||
// Get the parameter details
|
||||
node.value = token.match[2] !== undefined ? token.match[2] : (
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
token.match[6] !== undefined ? token.match[6] : (
|
||||
""
|
||||
)
|
||||
)
|
||||
)
|
||||
token.match[3] !== undefined ? token.match[3] : (
|
||||
token.match[4] !== undefined ? token.match[4] : (
|
||||
token.match[5] !== undefined ? token.match[5] : (
|
||||
token.match[6] !== undefined ? token.match[6] : (
|
||||
""
|
||||
)
|
||||
);
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(token.match[1]) {
|
||||
node.name = token.match[1];
|
||||
}
|
||||
@@ -206,28 +214,223 @@ exports.parseMacroParameter = function(source,pos) {
|
||||
Look for a macro invocation. Returns null if not found, or {type: "transclude", attributes:, start:, end:}
|
||||
*/
|
||||
exports.parseMacroInvocationAsTransclusion = function(source,pos) {
|
||||
var node = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(node) {
|
||||
var positionalName = 0,
|
||||
transclusion = {
|
||||
type: "transclude",
|
||||
start: node.start,
|
||||
end: node.end
|
||||
};
|
||||
$tw.utils.addAttributeToParseTreeNode(transclusion,"$variable",node.name);
|
||||
$tw.utils.each(node.params,function(param) {
|
||||
var name = param.name;
|
||||
if(name) {
|
||||
if(name.charAt(0) === "$") {
|
||||
name = "$" + name;
|
||||
}
|
||||
$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;
|
||||
var node = {
|
||||
type: "transclude",
|
||||
start: pos,
|
||||
attributes: {},
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reVarName = /([^\s>"'=:]+)/y;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double opening angle bracket
|
||||
var token = $tw.utils.parseTokenString(source,pos,"<<");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
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 >>, and that there is a closing >> somewhere ahead
|
||||
if(!(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
|
||||
if(source.indexOf(">>",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>"'=:)]+)/y;
|
||||
// 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>"'`=:]+)/y,
|
||||
reStrictIdentifier = /^[A-Za-z0-9\-_]+$/,
|
||||
reUnquotedAttribute = /(?!<<)((?:(?:>(?!>))|[^\s>"'])+)/y,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/y,
|
||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
|
||||
// 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,/=|:/y),
|
||||
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
|
||||
// Colon separator requires a strict identifier name to avoid mis-parsing values like $:/foo
|
||||
if(nameToken && separatorToken && separatorToken.match[0] === ":" && !reStrictIdentifier.test(nameToken.match[1])) {
|
||||
nameToken = null;
|
||||
separatorToken = null;
|
||||
}
|
||||
// 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);
|
||||
|
||||
do {
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
|
||||
if(isNewStyleSeparator) {
|
||||
// Look for a filtered value
|
||||
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
|
||||
if(filteredValue) {
|
||||
pos = filteredValue.end;
|
||||
node.type = "filtered";
|
||||
node.filter = filteredValue.match[1];
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for an MVV reference value
|
||||
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
|
||||
if(mvvReference) {
|
||||
pos = mvvReference.end;
|
||||
node.type = "macro";
|
||||
node.value = mvvReference;
|
||||
node.isMVV = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for a substituted value
|
||||
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
|
||||
if(substitutedValue) {
|
||||
pos = substitutedValue.end;
|
||||
node.type = "substituted";
|
||||
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
break; // redundant, but leaving for consistency
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
// Bail if we don't have a value
|
||||
if(!node.type) {
|
||||
return null;
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
@@ -296,7 +499,7 @@ exports.parseFilterVariable = function(source) {
|
||||
};
|
||||
|
||||
/*
|
||||
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:,}
|
||||
Look for an HTML attribute definition. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}
|
||||
*/
|
||||
exports.parseAttribute = function(source,pos) {
|
||||
var node = {
|
||||
@@ -346,19 +549,20 @@ exports.parseAttribute = function(source,pos) {
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} 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];
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocation(source,pos);
|
||||
if(macroInvocation) {
|
||||
pos = macroInvocation.end;
|
||||
// Look for an MVV reference value
|
||||
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
|
||||
if(mvvReference) {
|
||||
pos = mvvReference.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
node.value = mvvReference;
|
||||
node.isMVV = true;
|
||||
} else {
|
||||
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
|
||||
if(substitutedValue) {
|
||||
@@ -366,8 +570,19 @@ exports.parseAttribute = function(source,pos) {
|
||||
node.type = "substituted";
|
||||
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
// 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 if(source.charAt(pos) === "<" && source.charAt(pos + 1) === "<" && source.indexOf(">>",pos) !== -1) {
|
||||
// Value looks like a macro invocation (starts with << with a closing >> ahead) but does not parse as one. Return null so the enclosing tag fails to parse rather than silently binding the attribute to "true" and treating the remainder as further attributes (restores v5.3.8 behaviour)
|
||||
return null;
|
||||
} else {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +590,7 @@ exports.parseAttribute = function(source,pos) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there is no equals sign or colon, then this is an attribute with no value, defaulting to "true"
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
|
||||
@@ -11,11 +11,10 @@ The PDF parser embeds a PDF viewer
|
||||
|
||||
var ImageParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "iframe",
|
||||
attributes: {}
|
||||
},
|
||||
src;
|
||||
type: "element",
|
||||
tag: "iframe",
|
||||
attributes: {}
|
||||
};
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
} else if(text) {
|
||||
|
||||
@@ -11,14 +11,13 @@ The video parser parses a video tiddler into an embeddable HTML element
|
||||
|
||||
var VideoParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "video",
|
||||
attributes: {
|
||||
controls: {type: "string", value: "controls"},
|
||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||
}
|
||||
},
|
||||
src;
|
||||
type: "element",
|
||||
tag: "video",
|
||||
attributes: {
|
||||
controls: {type: "string", value: "controls"},
|
||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||
}
|
||||
};
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
} else if(text) {
|
||||
|
||||
@@ -46,10 +46,10 @@ exports.parse = function() {
|
||||
}
|
||||
// Return the $codeblock widget
|
||||
return [{
|
||||
type: "codeblock",
|
||||
attributes: {
|
||||
code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
|
||||
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
|
||||
}
|
||||
type: "codeblock",
|
||||
attributes: {
|
||||
code: {type: "string", value: text, start: codeStart, end: this.parser.pos},
|
||||
language: {type: "string", value: this.match[1], start: languageStart, end: languageEnd}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -51,10 +51,10 @@ exports.parse = function() {
|
||||
var commentStart = this.match.index;
|
||||
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||
return [{
|
||||
type: "void",
|
||||
children: [],
|
||||
text: this.parser.source.slice(commentStart, commentEnd),
|
||||
start: commentStart,
|
||||
end: commentEnd
|
||||
type: "void",
|
||||
children: [],
|
||||
text: this.parser.source.slice(commentStart, commentEnd),
|
||||
start: commentStart,
|
||||
end: commentEnd
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -44,9 +44,9 @@ exports.parse = function() {
|
||||
var commentStart = this.match.index;
|
||||
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||
return [{
|
||||
type: "void",
|
||||
text: this.parser.source.slice(commentStart, commentEnd),
|
||||
start: commentStart,
|
||||
end: commentEnd
|
||||
type: "void",
|
||||
text: this.parser.source.slice(commentStart, commentEnd),
|
||||
start: commentStart,
|
||||
end: commentEnd
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
// If we found an else then we need to parse the body looking for the endif
|
||||
var reEndString = "\\<\\%\\s*(endif)\\s*\\%\\>",
|
||||
ex;
|
||||
ex;
|
||||
if(hasLineBreak) {
|
||||
ex = this.parser.parseBlocksTerminatedExtended(reEndString);
|
||||
} else {
|
||||
|
||||
@@ -26,8 +26,6 @@ exports.init = function(parser) {
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
// Get all the details of the match
|
||||
var entityString = this.match[1];
|
||||
// Move past the macro call
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Return the entity
|
||||
|
||||
@@ -32,7 +32,7 @@ Instantiate parse rule
|
||||
exports.init = function(parser) {
|
||||
this.parser = parser;
|
||||
// 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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,7 +29,6 @@ exports.init = function(parser) {
|
||||
Parse the most recent match
|
||||
*/
|
||||
exports.parse = function() {
|
||||
var self = this;
|
||||
// Move past the pragma invocation
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
// Parse the filter terminated by a line break
|
||||
|
||||
@@ -37,7 +37,7 @@ exports.parse = function() {
|
||||
var paramString = this.match[2],
|
||||
params = [];
|
||||
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);
|
||||
while(paramMatch) {
|
||||
// Save the parameter details
|
||||
|
||||
95
core/modules/parsers/wikiparser/rules/mvvdisplayinline.js
Normal file
95
core/modules/parsers/wikiparser/rules/mvvdisplayinline.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/*\
|
||||
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}
|
||||
]
|
||||
}];
|
||||
};
|
||||
@@ -93,7 +93,7 @@ exports.parseLink = function(source,pos) {
|
||||
splitPos = null;
|
||||
}
|
||||
// Pull out the tooltip and URL
|
||||
var tooltip, URL, urlStart;
|
||||
var URL, urlStart;
|
||||
textNode.start = pos;
|
||||
if(splitPos) {
|
||||
urlStart = splitPos + 1;
|
||||
|
||||
@@ -67,5 +67,5 @@ exports.parse = function() {
|
||||
return [{
|
||||
type: "void",
|
||||
children: tree
|
||||
}]
|
||||
}];
|
||||
};
|
||||
|
||||
@@ -60,7 +60,7 @@ var processRow = function(prevColumns) {
|
||||
// End of row
|
||||
if(prevCell && colSpanCount > 1) {
|
||||
if(prevCell.attributes && prevCell.attributes && prevCell.attributes.colspan) {
|
||||
colSpanCount += prevCell.attributes.colspan.value;
|
||||
colSpanCount += prevCell.attributes.colspan.value;
|
||||
} else {
|
||||
colSpanCount -= 1;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ exports.parse = function() {
|
||||
table.children.splice(0,0,rowContainer); // Insert it at the bottom
|
||||
}
|
||||
// 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
|
||||
rowContainer.children = this.parser.parseInlineRun(rowTermRegExp,{eatTerminator: true});
|
||||
} else {
|
||||
|
||||
@@ -23,27 +23,6 @@ exports.init = function(parser) {
|
||||
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() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
@@ -53,17 +32,17 @@ exports.parse = function() {
|
||||
params = this.match[3] ? this.match[3].split("|") : [];
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "transclude",
|
||||
attributes: {},
|
||||
isBlock: true
|
||||
};
|
||||
type: "transclude",
|
||||
attributes: {},
|
||||
isBlock: true
|
||||
};
|
||||
$tw.utils.each(params,function(paramValue,index) {
|
||||
var name = "" + index;
|
||||
transcludeNode.attributes[name] = {
|
||||
name: name,
|
||||
type: "string",
|
||||
value: paramValue
|
||||
}
|
||||
};
|
||||
});
|
||||
// Prepare the tiddler widget
|
||||
var tr, targetTitle, targetField, targetIndex, tiddlerNode;
|
||||
|
||||
@@ -23,27 +23,6 @@ exports.init = function(parser) {
|
||||
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() {
|
||||
// Move past the match
|
||||
this.parser.pos = this.matchRegExp.lastIndex;
|
||||
@@ -53,16 +32,16 @@ exports.parse = function() {
|
||||
params = this.match[3] ? this.match[3].split("|") : [];
|
||||
// Prepare the transclude widget
|
||||
var transcludeNode = {
|
||||
type: "transclude",
|
||||
attributes: {}
|
||||
};
|
||||
type: "transclude",
|
||||
attributes: {}
|
||||
};
|
||||
$tw.utils.each(params,function(paramValue,index) {
|
||||
var name = "" + index;
|
||||
transcludeNode.attributes[name] = {
|
||||
name: name,
|
||||
type: "string",
|
||||
value: paramValue
|
||||
}
|
||||
};
|
||||
});
|
||||
// Prepare the tiddler widget
|
||||
var tr, targetTitle, targetField, targetIndex, tiddlerNode;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user