mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-02-19 16:39:50 +00:00
Compare commits
176 Commits
new-releas
...
eslint-fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5deb88ad54 | ||
|
|
450a99b289 | ||
|
|
08f2b8bdf4 | ||
|
|
c305eb01eb | ||
|
|
71462143bf | ||
|
|
909149a347 | ||
|
|
a2543cfd4a | ||
|
|
b713d13c5a | ||
|
|
bb05bd8817 | ||
|
|
42a908e1c9 | ||
|
|
70689a6de4 | ||
|
|
64ee20edd2 | ||
|
|
0177f09823 | ||
|
|
643cabf9c8 | ||
|
|
5cf3fcd843 | ||
|
|
67f13c585d | ||
|
|
1bbb7fd53b | ||
|
|
599933c34d | ||
|
|
b1ccb82e0a | ||
|
|
ea648c7d15 | ||
|
|
a3a4e91751 | ||
|
|
c96d398712 | ||
|
|
821dcaf002 | ||
|
|
9247a87e11 | ||
|
|
bda54b0ad5 | ||
|
|
cd8b1faa74 | ||
|
|
0673426f5a | ||
|
|
d376ada241 | ||
|
|
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 | ||
|
|
eb3a80968e | ||
|
|
62ae4b24bc | ||
|
|
ded76aa84f | ||
|
|
79e3d14698 | ||
|
|
763d717a13 | ||
|
|
e42ed6808e | ||
|
|
844564180f | ||
|
|
a670de0e95 | ||
|
|
faee49ee01 | ||
|
|
dd20be49f0 | ||
|
|
a27f74bbdc | ||
|
|
ae4e99951a | ||
|
|
be84dee26b | ||
|
|
00e17874f0 | ||
|
|
9041f099a3 | ||
|
|
3ba31be2a8 | ||
|
|
99d8afd515 | ||
|
|
2ab5f26644 | ||
|
|
419fe68ee2 | ||
|
|
0e765bdbdb | ||
|
|
855d8a9638 | ||
|
|
afcf108d29 | ||
|
|
8f9acc0ca2 | ||
|
|
5e4b8fbb3c | ||
|
|
8e301178a4 | ||
|
|
a72d3a09bf | ||
|
|
56634ffe29 | ||
|
|
24c317e1ab | ||
|
|
07329c6849 | ||
|
|
47ab3476f6 | ||
|
|
f0e64660f2 | ||
|
|
9663e65f4b | ||
|
|
7cb422242a | ||
|
|
f075f24e6b | ||
|
|
5fa1098c03 | ||
|
|
92dc927c7b | ||
|
|
98a61f01bb | ||
|
|
f3fa69e229 | ||
|
|
e2fb22ade0 | ||
|
|
7fb8560908 | ||
|
|
ff7814360e | ||
|
|
2d9303c6ff | ||
|
|
6aee5eb0c7 | ||
|
|
6eb881bffe | ||
|
|
2a5ce95d99 | ||
|
|
bd4fdd8f2e | ||
|
|
09379abd5d | ||
|
|
c6906120d8 | ||
|
|
c4c60933f4 | ||
|
|
a3979cda9c | ||
|
|
3c8ee86e23 | ||
|
|
921c0174fb | ||
|
|
4196d96adc | ||
|
|
743e99d12d | ||
|
|
6beeb23d10 | ||
|
|
838fad916d | ||
|
|
935e89bd93 | ||
|
|
1b8a2caa23 | ||
|
|
ecba671bcf | ||
|
|
fc1e53a777 | ||
|
|
2b6bdcbf97 | ||
|
|
119706a918 | ||
|
|
86d15585b6 | ||
|
|
4b824795c8 | ||
|
|
cd173a959d | ||
|
|
86d61e09bd | ||
|
|
7c197f6ecc | ||
|
|
8f8b46dab7 | ||
|
|
7b013af240 | ||
|
|
05f3e6d5a0 | ||
|
|
48eeb4603a | ||
|
|
fc74219c0b | ||
|
|
86c4770a28 | ||
|
|
ffde2da16c | ||
|
|
da41a55f29 | ||
|
|
846ac9a0dd | ||
|
|
65edda224b | ||
|
|
41dac42f3b | ||
|
|
87d9754a4e | ||
|
|
5cd3084298 | ||
|
|
4c27c09b4d | ||
|
|
4bb0bc5527 | ||
|
|
6cb333b65b | ||
|
|
3378497816 | ||
|
|
033d5cf225 | ||
|
|
52d73eb1a8 | ||
|
|
5d1c1eaf87 | ||
|
|
ed4a186c9c | ||
|
|
f16c0d769b | ||
|
|
298508c104 | ||
|
|
f1e1532949 | ||
|
|
3e1078eff1 | ||
|
|
cc348fee96 | ||
|
|
24d45fd318 | ||
|
|
9fd345ec06 | ||
|
|
30e9b4f3b7 | ||
|
|
c6556d5207 | ||
|
|
a8da7e0207 | ||
|
|
d5762b1fbb | ||
|
|
2b0739f06e | ||
|
|
d81204c6ab | ||
|
|
e339f112a4 | ||
|
|
e001c21bf5 | ||
|
|
7a9235e9d1 | ||
|
|
bbbc8c2c03 | ||
|
|
538482e9a9 | ||
|
|
df7973fc3e | ||
|
|
ae79736e82 | ||
|
|
102c236267 | ||
|
|
06a2923adf | ||
|
|
244251ed44 | ||
|
|
9164f305e0 | ||
|
|
64f86c2187 | ||
|
|
54e5ef7489 | ||
|
|
2d2ba61949 | ||
|
|
0bbe170cf0 | ||
|
|
6f306d1ed6 | ||
|
|
845f988ab0 | ||
|
|
234667cc31 | ||
|
|
f1ce35036e | ||
|
|
5dfdbc8ea0 | ||
|
|
4d4d9d9995 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
boot/** -linguist-generated
|
||||
**/tiddlywiki.files linguist-language=JSON
|
||||
**/tiddlywiki.info linguist-language=JSON
|
||||
**/plugin.info linguist-language=JSON
|
||||
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[Report] "
|
||||
type: report
|
||||
|
||||
---
|
||||
|
||||
<!-- Remove elements, that you do not need -->
|
||||
<!-- Add screenshots where needed -->
|
||||
|
||||
**Problem Description**
|
||||
<!-- Describe your problem: A clear and concise description of what your problem is -->
|
||||
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. At https://tiddlywiki.com
|
||||
2. Click on ...
|
||||
3. Scroll down to ...
|
||||
4. See ...
|
||||
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
As a user,
|
||||
<!-- As a developer, -->
|
||||
I would expect ...
|
||||
|
||||
|
||||
**TiddlyWiki Configuration**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
|
||||
|
||||
<!-- Your report comes here -->
|
||||
<!-- or -->
|
||||
<!-- Add it manually -->
|
||||
|
||||
- Version: <!-- e.g. v5.3.8 -->
|
||||
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
|
||||
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
|
||||
|
||||
|
||||
**Desktop**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- OS: <!-- e.g. iOS -->
|
||||
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
|
||||
|
||||
**Smartphone**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Device: <!-- e.g. iPhone6 -->
|
||||
- OS: <!-- e.g. iOS8.1 -->
|
||||
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
|
||||
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
||||
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,67 +0,0 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[BUG] "
|
||||
body:
|
||||
- type: textarea
|
||||
id: Describe
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: Expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Reproduce
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: "Steps to reproduce the behavior:"
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: Drag image here to upload screenshot!
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Configuration
|
||||
attributes:
|
||||
label: TiddlyWiki Configuration
|
||||
description: please complete the following information
|
||||
placeholder: |
|
||||
- Version [e.g. v5.1.24]
|
||||
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
|
||||
- Plugins installed [e.g. Freelinks, TiddlyMap]
|
||||
|
||||
### Desktop (please complete the following information):
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### Smartphone (please complete the following information):
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: Context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -4,17 +4,23 @@ about: Suggest an idea for TiddlyWiki 5
|
||||
title: "[IDEA]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
type: idea
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
**Is your idea related to a problem? Please describe.**
|
||||
|
||||
A clear and concise description of what the problem is. Eg:
|
||||
As a user, I would like [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
2
.github/workflows/pr-check-build-size.yml
vendored
2
.github/workflows/pr-check-build-size.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
steps:
|
||||
- name: build-size-check
|
||||
id: get_sizes
|
||||
uses: TiddlyWiki/cerebrus@v4
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
||||
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@v4
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
||||
18
.github/workflows/pr-path-validation.yml
vendored
18
.github/workflows/pr-path-validation.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Validate PR Paths
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
validate-pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Validate PR
|
||||
uses: TiddlyWiki/cerebrus@v4
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.base_ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
37
.github/workflows/pr-validation.yml
vendored
Normal file
37
.github/workflows/pr-validation.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: PR Validation
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
jobs:
|
||||
validate-pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Step 1: Validate PR paths
|
||||
- name: Validate PR Paths
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: rules
|
||||
continue-on-error: true
|
||||
|
||||
# Step 2: Validate change notes
|
||||
- name: Validate Change Notes
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: changenotes
|
||||
continue-on-error: false
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
127
boot/boot.js
127
boot/boot.js
@@ -8,6 +8,8 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
|
||||
|
||||
\*/
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
|
||||
var _boot = (function($tw) {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
@@ -35,7 +37,7 @@ if($tw.node) {
|
||||
$tw.boot.log = function(str) {
|
||||
$tw.boot.logMessages = $tw.boot.logMessages || [];
|
||||
$tw.boot.logMessages.push(str);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an object has a property
|
||||
@@ -44,12 +46,8 @@ $tw.utils.hop = function(object,property) {
|
||||
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
|
||||
};
|
||||
|
||||
/*
|
||||
Determine if a value is an array
|
||||
*/
|
||||
$tw.utils.isArray = function(value) {
|
||||
return Object.prototype.toString.call(value) == "[object Array]";
|
||||
};
|
||||
/** @deprecated Use Array.isArray instead */
|
||||
$tw.utils.isArray = (value) => Array.isArray(value);
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
@@ -128,35 +126,22 @@ $tw.utils.pushTop = function(array,value) {
|
||||
return array;
|
||||
};
|
||||
|
||||
/*
|
||||
Determine if a value is a date
|
||||
*/
|
||||
$tw.utils.isDate = function(value) {
|
||||
return Object.prototype.toString.call(value) === "[object Date]";
|
||||
};
|
||||
/** @deprecated Use instanceof Date instead */
|
||||
$tw.utils.isDate = (value) => value instanceof Date;
|
||||
|
||||
/*
|
||||
Iterate through all the own properties of an object or array. Callback is invoked with (element,title,object)
|
||||
*/
|
||||
/** @deprecated Use array iterative methods instead */
|
||||
$tw.utils.each = function(object,callback) {
|
||||
var next,f,length;
|
||||
if(object) {
|
||||
if(Object.prototype.toString.call(object) == "[object Array]") {
|
||||
for(f=0, length=object.length; f<length; f++) {
|
||||
next = callback(object[f],f,object);
|
||||
if(next === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(Array.isArray(object)) {
|
||||
object.every((element,index,array) => {
|
||||
const next = callback(element,index,array);
|
||||
return next !== false;
|
||||
});
|
||||
} else {
|
||||
var keys = Object.keys(object);
|
||||
for(f=0, length=keys.length; f<length; f++) {
|
||||
var key = keys[f];
|
||||
next = callback(object[key],key,object);
|
||||
if(next === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Object.entries(object).every((entry) => {
|
||||
const next = callback(entry[1], entry[0], object);
|
||||
return next !== false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -335,28 +320,26 @@ $tw.utils.htmlDecode = function(s) {
|
||||
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() {
|
||||
var href = window.location.href;
|
||||
var idx = href.indexOf('#');
|
||||
const href = window.location.href,
|
||||
idx = href.indexOf("#");
|
||||
|
||||
if(idx === -1) {
|
||||
return "#";
|
||||
} else if(href.substr(idx + 1,1) === "#" || href.substr(idx + 1,3) === "%23") {
|
||||
}
|
||||
|
||||
const afterHash = href.substring(idx + 1);
|
||||
if(afterHash.startsWith("#") || afterHash.startsWith("%23")) {
|
||||
// Special case: ignore location hash if it itself starts with a #
|
||||
return "#";
|
||||
} else {
|
||||
return href.substring(idx);
|
||||
}
|
||||
return href.substring(idx);
|
||||
};
|
||||
|
||||
/*
|
||||
Pad a string to a given length with "0"s. Length defaults to 2
|
||||
*/
|
||||
$tw.utils.pad = function(value,length) {
|
||||
length = length || 2;
|
||||
var s = value.toString();
|
||||
if(s.length < length) {
|
||||
s = "000000000000000000000000000".substr(0,length - s.length) + s;
|
||||
}
|
||||
return s;
|
||||
|
||||
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
|
||||
$tw.utils.pad = function(value,length = 2) {
|
||||
const s = value.toString();
|
||||
return s.padStart(length, "0");
|
||||
};
|
||||
|
||||
// Convert a date into UTC YYYYMMDDHHMMSSmmm format
|
||||
@@ -582,7 +565,7 @@ using a lowercase extension only.
|
||||
*/
|
||||
$tw.utils.getFileExtensionInfo = function(ext) {
|
||||
return ext ? $tw.config.fileExtensionInfo[ext.toLowerCase()] : null;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Given an extension, get the correct encoding for that file.
|
||||
@@ -605,7 +588,7 @@ var globalCheck =[
|
||||
" delete Object.prototype.__temp__;",
|
||||
" }",
|
||||
" delete Object.prototype.__temp__;",
|
||||
].join('\n');
|
||||
].join("\n");
|
||||
|
||||
/*
|
||||
Run code globally with specified context variables in scope
|
||||
@@ -630,10 +613,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);
|
||||
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);
|
||||
}
|
||||
@@ -790,7 +773,7 @@ $tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
|
||||
promptInfo.form.parentNode.removeChild(promptInfo.form);
|
||||
this.setWrapperDisplay();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Crypto helper object for encrypted content. It maintains the password text in a closure, and provides methods to change
|
||||
@@ -829,7 +812,7 @@ $tw.utils.Crypto = function() {
|
||||
};
|
||||
this.hasPassword = function() {
|
||||
return !!currentPassword;
|
||||
}
|
||||
};
|
||||
this.encrypt = function(text,password) {
|
||||
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
|
||||
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
|
||||
@@ -847,7 +830,7 @@ Execute the module named 'moduleName'. The name can optionally be relative to th
|
||||
$tw.modules.execute = function(moduleName,moduleRoot) {
|
||||
var name = moduleName;
|
||||
if(moduleName.charAt(0) === ".") {
|
||||
name = $tw.utils.resolvePath(moduleName,moduleRoot)
|
||||
name = $tw.utils.resolvePath(moduleName,moduleRoot);
|
||||
}
|
||||
if(!$tw.modules.titles[name]) {
|
||||
if($tw.modules.titles[name + ".js"]) {
|
||||
@@ -1218,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
|
||||
@@ -1228,7 +1211,7 @@ $tw.Wiki = function(options) {
|
||||
tiddler: tiddler,
|
||||
shadow: this.isShadowTiddler(title),
|
||||
exists: this.tiddlerExists(title)
|
||||
}
|
||||
};
|
||||
// Update indexes
|
||||
this.clearCache(title);
|
||||
this.clearGlobalCache();
|
||||
@@ -1253,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
|
||||
@@ -1268,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();
|
||||
@@ -1476,11 +1459,11 @@ $tw.Wiki = function(options) {
|
||||
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;
|
||||
@@ -1587,7 +1570,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
|
||||
// Assemble a report tiddler
|
||||
var titleReportTiddler = "TiddlyWiki Safe Mode",
|
||||
report = [];
|
||||
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:")
|
||||
report.push("TiddlyWiki has been started in [[safe mode|https://tiddlywiki.com/static/SafeMode.html]]. All plugins are temporarily disabled. Most customisations have been disabled by renaming the following tiddlers:");
|
||||
// Delete the overrides
|
||||
overrides.forEach(function(title) {
|
||||
var tiddler = self.getTiddler(title),
|
||||
@@ -1596,7 +1579,7 @@ $tw.Wiki.prototype.processSafeMode = function() {
|
||||
self.addTiddler(new $tw.Tiddler(tiddler, {title: newTitle}));
|
||||
report.push("* [[" + title + "|" + newTitle + "]]");
|
||||
});
|
||||
report.push()
|
||||
report.push();
|
||||
this.addTiddler(new $tw.Tiddler({title: titleReportTiddler, text: report.join("\n\n")}));
|
||||
// Set $:/DefaultTiddlers to point to our report
|
||||
this.addTiddler(new $tw.Tiddler({title: "$:/DefaultTiddlers", text: "[[" + titleReportTiddler + "]]"}));
|
||||
@@ -2030,7 +2013,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
|
||||
break;
|
||||
case "filepath":
|
||||
value = path.relative(rootPath, filename).split(path.sep).join('/');
|
||||
value = path.relative(rootPath, filename).split(path.sep).join("/");
|
||||
break;
|
||||
case "filename":
|
||||
value = path.basename(filename);
|
||||
@@ -2083,7 +2066,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
}
|
||||
});
|
||||
return arrayOfFiles;
|
||||
}
|
||||
};
|
||||
// Process the listed tiddlers
|
||||
$tw.utils.each(filesInfo.tiddlers,function(tidInfo) {
|
||||
if(tidInfo.prefix && tidInfo.suffix) {
|
||||
@@ -2192,7 +2175,7 @@ Returns the path of the plugin folder
|
||||
$tw.findLibraryItem = function(name,paths) {
|
||||
var pathIndex = 0;
|
||||
do {
|
||||
var pluginPath = path.resolve(paths[pathIndex],"./" + name)
|
||||
var pluginPath = path.resolve(paths[pathIndex],"./" + name);
|
||||
if(fs.existsSync(pluginPath) && fs.statSync(pluginPath).isDirectory()) {
|
||||
return pluginPath;
|
||||
}
|
||||
@@ -2551,7 +2534,7 @@ $tw.boot.initStartup = function(options) {
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
$tw.boot.loadStartup = function(options){
|
||||
@@ -2568,7 +2551,7 @@ $tw.boot.loadStartup = function(options){
|
||||
}
|
||||
// Give hooks a chance to modify the store
|
||||
$tw.hooks.invokeHook("th-boot-tiddlers-loaded");
|
||||
}
|
||||
};
|
||||
$tw.boot.execStartup = function(options){
|
||||
// Unpack plugin tiddlers
|
||||
$tw.wiki.readPluginInfo();
|
||||
@@ -2598,7 +2581,7 @@ $tw.boot.execStartup = function(options){
|
||||
$tw.boot.disabledStartupModules = $tw.boot.disabledStartupModules || [];
|
||||
// Repeatedly execute the next eligible task
|
||||
$tw.boot.executeNextStartupTask(options.callback);
|
||||
}
|
||||
};
|
||||
/*
|
||||
Startup TiddlyWiki
|
||||
*/
|
||||
@@ -2617,7 +2600,7 @@ $tw.addUnloadTask = function(task) {
|
||||
if($tw.unloadTasks.indexOf(task) === -1) {
|
||||
$tw.unloadTasks.push(task);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the remaining eligible startup tasks
|
||||
@@ -2664,7 +2647,7 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
||||
}
|
||||
taskIndex++;
|
||||
}
|
||||
if(typeof callback === 'function') {
|
||||
if(typeof callback === "function") {
|
||||
callback();
|
||||
}
|
||||
return false;
|
||||
@@ -2801,6 +2784,8 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) !== "undefined") {
|
||||
exports.TiddlyWiki = _boot;
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,8 @@ See Boot.js for further details of the boot process.
|
||||
|
||||
\*/
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
|
||||
var _bootprefix = (function($tw) {
|
||||
|
||||
"use strict";
|
||||
@@ -114,6 +116,8 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) === "undefined") {
|
||||
// Set up $tw global for the browser
|
||||
window.$tw = _bootprefix(window.$tw);
|
||||
|
||||
14
community/people/ChristianByron.tid
Normal file
14
community/people/ChristianByron.tid
Normal file
@@ -0,0 +1,14 @@
|
||||
title: @Christian_Byron
|
||||
tags: Community/Person
|
||||
fullname: Christian Byron
|
||||
talk.tiddlywiki.org: Christian_Byron
|
||||
github: ceebeetree
|
||||
linkedin: www.linkedin.com/in/christian-byron-b84a594/
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEBAAMBAAAAAAAAAAAAAAAHBgEDBQQBAAMBAAAAAAAAAAAAAAAAAAABAwX/2gAMAwEAAhADEAAAADv2xtJlY03sqePW3ARS1RSydIhcH//EACcQAAICAgIBAgYDAAAAAAAAAAECAwQFEQASMRMhBhBBk8HRIzJx/9oACAEBAAE/AMFQxs+NExqJLMCwYE+SOT4bF3qr+hAIpRsDQ6lWH0Yco4S/eVniRVQHXZzrZ5dwGQpQtNII2RfJVvHMRl5cbKxC94n/ALp+RxfiKpNcgMMUqPIwjcnWip/I5XtUowaL3Ujir/xt79Glb6/4OZ7MV5oEpUzuIa7MPB14A5jpoYLsEsydo1bbLre+CWEEEYab7Uf74ZYSSThpvtR/vmRmhnuzywp1jZtquta+VPM49qlcy24lf017At7g8uZnHrUsGK3Ez+m3UBvcnXy//8QAHhEAAgEFAAMAAAAAAAAAAAAAAQIDAAQRIkEyUaH/2gAIAQIBAT8AmiuVlZkLEeQOflJPcvMAF0z65V+h0YIW52rBDuxUrztf/8QAIxEBAAEDAwMFAAAAAAAAAAAAAgEAAxEEBSMSQcEiMVJxof/aAAgBAwEBPwC/Z1ZvNBOYz1Gc/lDUat3ySPRM/H2P3W4hcbIldpxnxW3BcjQk9oznzX//2Q==
|
||||
|
||||
Hello ~TiddlyWikiers - I have been a long time fan, recent contributor to the TW community.
|
||||
Recently I have volunteered to run the [[TiddlyWiki Newsletter|https://tiddlywiki.substack.com/]] to spread the great news about TW.
|
||||
|
||||
I have been in the IT industry for about thirty years, mostly as a consultant and technical arcitect.
|
||||
More recently I went back to study a masters in IT focussing on AI and data science.
|
||||
Now my partner and I have started our own business ([[Sphere Innovations|https://sphere-innovations.com.au]]) - in consulting and building web applications for small to medium size businesses here in Australia.
|
||||
19
community/people/LinOnetwo.tid
Normal file
19
community/people/LinOnetwo.tid
Normal file
@@ -0,0 +1,19 @@
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
|
||||
created: 20251110102157310
|
||||
first-sighting: 2019-03-01
|
||||
fullname: Lin Onetwo
|
||||
github: linonetwo
|
||||
homepage: https://wiki.onetwo.website/
|
||||
modified: 20251111184556193
|
||||
tags: Community/Person Community/Team/Contributors
|
||||
talk.tiddlywiki.org: linonetwo
|
||||
title: @linonetwo
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I don’t want to forget any of them. When I’m deeply focused on a task, it’s easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
|
||||
|
||||
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
|
||||
|
||||
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, I’ve enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
|
||||
|
||||
Most of my notes are open by default and shared publicly on my homepage as a digital garden.
|
||||
25
community/people/PMario.tid
Normal file
25
community/people/PMario.tid
Normal file
@@ -0,0 +1,25 @@
|
||||
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
|
||||
created: 20251110102157310
|
||||
first-sighting: 2009-11-14
|
||||
fullname: Mario Pietsch
|
||||
github: pmario
|
||||
homepage: https://wikilabs.github.io/
|
||||
modified: 20251110124935183
|
||||
tags: Community/Person Community/Team/Contributors
|
||||
talk.tiddlywiki.org: pmario
|
||||
title: @pmario
|
||||
type: text/vnd.tiddlywiki
|
||||
youtube: https://www.youtube.com/@pmario
|
||||
|
||||
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
|
||||
|
||||
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
|
||||
|
||||
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
|
||||
|
||||
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what that’s good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
|
||||
|
||||
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
|
||||
|
||||
Have fun!<br>
|
||||
Mario
|
||||
19
community/project/teams/Developer Experience Team.tid
Normal file
19
community/project/teams/Developer Experience Team.tid
Normal file
@@ -0,0 +1,19 @@
|
||||
title: Developer Experience Team
|
||||
tags: Community/Team
|
||||
modified: 20251109200632671
|
||||
created: 20251109200632671
|
||||
leader: @pmario
|
||||
team: @saqimtiaz
|
||||
|
||||
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
|
||||
|
||||
Tools and resources managed by the Developer Experience Team include:
|
||||
|
||||
* Advising and assisting contributors, particularly new developers
|
||||
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
|
||||
** Development environment setup guides
|
||||
** Code review processes and best practices
|
||||
** Contribution guidelines and documentation
|
||||
* Continuous integration and deployment scripts providing feedback on pull requests
|
||||
* Devising and implementing labelling systems for issues and pull requests
|
||||
* Automation scripts to simplify common development tasks
|
||||
@@ -1,8 +1,8 @@
|
||||
title: Infrastructure Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
modified: 20251110133437795
|
||||
tags: Community/Team
|
||||
team: @MotovunJack
|
||||
title: Infrastructure Team
|
||||
|
||||
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
|
||||
|
||||
@@ -12,3 +12,4 @@ The infrastructure includes:
|
||||
* github.com/TiddlyWiki
|
||||
* tiddlywiki.com DNS
|
||||
* Netlify account for PR previews
|
||||
* edit.tiddlywiki.com
|
||||
@@ -1,6 +0,0 @@
|
||||
title: Newsletter Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
|
||||
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.
|
||||
11
community/project/teams/Quality Assurance Team.tid
Normal file
11
community/project/teams/Quality Assurance Team.tid
Normal file
@@ -0,0 +1,11 @@
|
||||
title: Quality Assurance Team
|
||||
created: 20251112125742296
|
||||
modified: 20251112125742296
|
||||
tags: Community/Team
|
||||
team:
|
||||
leader: @Leilei332
|
||||
|
||||
title: Quality Assurance Team
|
||||
|
||||
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.
|
||||
|
||||
15
community/project/teams/TiddlyWiki Newsletter Team.tid
Normal file
15
community/project/teams/TiddlyWiki Newsletter Team.tid
Normal file
@@ -0,0 +1,15 @@
|
||||
title: TiddlyWiki Newsletter Team
|
||||
tags: Community/Team
|
||||
modified: 20251219090709874
|
||||
created: 20250909171928024
|
||||
leader: @Christian_Byron
|
||||
|
||||
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
|
||||
|
||||
! Audience
|
||||
|
||||
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
|
||||
|
||||
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
|
||||
|
||||
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.
|
||||
@@ -1,5 +1,5 @@
|
||||
title: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Infrastructure Team]] [[Succession Team]]
|
||||
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
|
||||
|
||||
|
||||
@@ -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 + "'";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -7,59 +7,59 @@ Render individual tiddlers and save the results to the specified files
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var widget = require("$:/core/modules/widgets/widget.js");
|
||||
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;
|
||||
|
||||
@@ -7,57 +7,57 @@ Saves individual tiddlers in their raw text or binary format to the specified fi
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "save",
|
||||
synchronous: true
|
||||
};
|
||||
exports.info = {
|
||||
name: "save",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
var Command = function(params,commander,callback) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
if(this.params.length < 1) {
|
||||
return "Missing filename filter";
|
||||
}
|
||||
var self = this,
|
||||
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,
|
||||
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
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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,7 +177,7 @@ 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));
|
||||
});
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ exports.getSubdirectories = function(dirPath) {
|
||||
}
|
||||
});
|
||||
return subdirs;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Recursively (and synchronously) copy a directory and all its content
|
||||
@@ -83,7 +83,7 @@ exports.copyFile = function(srcPath,dstPath) {
|
||||
dstFile = fs.openSync(dstPath,"w"),
|
||||
bytesRead = 1,
|
||||
pos = 0;
|
||||
while (bytesRead > 0) {
|
||||
while(bytesRead > 0) {
|
||||
bytesRead = fs.readSync(srcFile,fileBuffer,0,FILE_BUFFER_LENGTH,pos);
|
||||
fs.writeSync(dstFile,fileBuffer,0,bytesRead);
|
||||
pos += bytesRead;
|
||||
@@ -148,7 +148,7 @@ exports.deleteDirectory = function(dirPath) {
|
||||
fs.unlinkSync(currPath);
|
||||
}
|
||||
}
|
||||
fs.rmdirSync(dirPath);
|
||||
fs.rmdirSync(dirPath);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -255,7 +255,7 @@ exports.generateTiddlerFileInfo = function(tiddler,options) {
|
||||
// Overriding to the .tid extension needs special handling
|
||||
fileInfo.type = "application/x-tiddler";
|
||||
fileInfo.hasMetaFile = false;
|
||||
} else if (metaExt === ".json") {
|
||||
} else if(metaExt === ".json") {
|
||||
// Overriding to the .json extension needs special handling
|
||||
fileInfo.type = "application/json";
|
||||
fileInfo.hasMetaFile = false;
|
||||
@@ -345,18 +345,18 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
// Replace any Windows control codes
|
||||
filepath = filepath.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i,"_$1_");
|
||||
// Replace any leading spaces with the same number of underscores
|
||||
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_")});
|
||||
filepath = filepath.replace(/^ +/,function (u) { return u.replace(/ /g, "_");});
|
||||
//If the path does not start with "." or ".." && a path seperator, then
|
||||
if(!/^\.{1,2}[/\\]/g.test(filepath)) {
|
||||
// Don't let the filename start with any dots because such files are invisible on *nix
|
||||
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_")});
|
||||
filepath = filepath.replace(/^\.+/g,function (u) { return u.replace(/\./g, "_");});
|
||||
}
|
||||
// Replace any Unicode control codes
|
||||
filepath = filepath.replace(/[\x00-\x1f\x80-\x9f]/g,"_");
|
||||
// Replace any characters that can't be used in cross-platform filenames
|
||||
filepath = $tw.utils.transliterate(filepath.replace(/<|>|~|\:|\"|\||\?|\*|\^/g,"_"));
|
||||
// Replace any dots or spaces at the end of the extension with the same number of underscores
|
||||
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_")});
|
||||
extension = extension.replace(/[\. ]+$/, function (u) { return u.replace(/[\. ]/g, "_");});
|
||||
// Truncate the extension if it is too long
|
||||
if(extension.length > 32) {
|
||||
extension = extension.substr(0,32);
|
||||
@@ -382,9 +382,9 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
}
|
||||
// Add a uniquifier if the file already exists (default)
|
||||
var fullPath = path.resolve(directory, filepath + extension);
|
||||
if (!overwrite) {
|
||||
if(!overwrite) {
|
||||
var oldPath = (options.fileInfo) ? options.fileInfo.filepath : undefined,
|
||||
count = 0;
|
||||
count = 0;
|
||||
do {
|
||||
fullPath = path.resolve(directory,filepath + (count ? "_" + count : "") + extension);
|
||||
if(oldPath && oldPath == fullPath) break;
|
||||
@@ -401,7 +401,7 @@ exports.generateTiddlerFilepath = function(title,options) {
|
||||
writePath.indexOf(path.resolve(directory)) == 0 ||
|
||||
writePath.indexOf(path.resolve($tw.boot.wikiPath)) == 0 ||
|
||||
writePath.indexOf(path.resolve($tw.boot.wikiTiddlersPath,originalpath)) == 0 );
|
||||
}
|
||||
}
|
||||
if(encode) {
|
||||
writePath = path.resolve(directory,$tw.utils.encodeURIComponentExtended(fullPath));
|
||||
}
|
||||
@@ -521,12 +521,12 @@ Cleanup old files on disk, by comparing the options values:
|
||||
*/
|
||||
exports.cleanupTiddlerFiles = function(options,callback) {
|
||||
var adaptorInfo = options.adaptorInfo || {},
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
bootInfo = options.bootInfo || {},
|
||||
title = options.title || "undefined";
|
||||
if(adaptorInfo.filepath && bootInfo.filepath && adaptorInfo.filepath !== bootInfo.filepath) {
|
||||
$tw.utils.deleteTiddlerFile(adaptorInfo,function(err) {
|
||||
if(err) {
|
||||
if ((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
if((err.code == "EPERM" || err.code == "EACCES") && err.syscall == "unlink") {
|
||||
// Error deleting the previous file on disk, should fail gracefully
|
||||
$tw.syncer.displayError("Server desynchronized. Error cleaning up previous file for tiddler: \""+title+"\"",err);
|
||||
return callback(null,bootInfo);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -41,7 +41,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 +62,9 @@ function Server(options) {
|
||||
this.authorizationPrincipals = {
|
||||
readers: (this.get("readers") || authorizedUserName).split(",").map($tw.utils.trim),
|
||||
writers: (this.get("writers") || authorizedUserName).split(",").map($tw.utils.trim)
|
||||
}
|
||||
};
|
||||
if(this.get("admin") || authorizedUserName !== "(anon)") {
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(',').map($tw.utils.trim)
|
||||
this.authorizationPrincipals["admin"] = (this.get("admin") || authorizedUserName).split(",").map($tw.utils.trim);
|
||||
}
|
||||
// Load and initialise authenticators
|
||||
$tw.modules.forEachModuleOfType("authenticator", function(title,authenticatorDefinition) {
|
||||
@@ -89,7 +91,7 @@ function Server(options) {
|
||||
this.listenOptions = {
|
||||
key: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsKeyFilepath),"utf8"),
|
||||
cert: fs.readFileSync(path.resolve(this.boot.wikiPath,tlsCertFilepath),"utf8"),
|
||||
passphrase: tlsPassphrase || ''
|
||||
passphrase: tlsPassphrase || ""
|
||||
};
|
||||
this.protocol = "https";
|
||||
}
|
||||
@@ -114,7 +116,7 @@ encoding: the encoding of the data to send (passed to the end method of the resp
|
||||
*/
|
||||
function sendResponse(request,response,statusCode,headers,data,encoding) {
|
||||
if(this.enableBrowserCache && (statusCode == 200)) {
|
||||
var hash = crypto.createHash('md5');
|
||||
var hash = crypto.createHash("md5");
|
||||
// Put everything into the hash that could change and invalidate the data that
|
||||
// the browser already stored. The headers the data and the encoding.
|
||||
hash.update(data);
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
30
core-server/utils/base64.js
Normal file
30
core-server/utils/base64.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*\
|
||||
title: $:/core-modules/modules/utils/base64.js
|
||||
type: application/javascript
|
||||
module-type: utils-node
|
||||
|
||||
Base64 UTF-8 utlity functions.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { TextEncoder, TextDecoder } = require("node:util");
|
||||
|
||||
exports.btoa = (binstr) => Buffer.from(binstr, "binary").toString("base64");
|
||||
|
||||
exports.atob = (b64) => Buffer.from(b64, "base64").toString("binary");
|
||||
|
||||
function base64ToBytes(base64) {
|
||||
const binString = exports.atob(base64);
|
||||
return Uint8Array.from(binString, (m) => m.codePointAt(0));
|
||||
};
|
||||
|
||||
function bytesToBase64(bytes) {
|
||||
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
|
||||
return exports.btoa(binString);
|
||||
};
|
||||
|
||||
exports.base64EncodeUtf8 = (str) => bytesToBase64(new TextEncoder().encode(str));
|
||||
|
||||
exports.base64DecodeUtf8 = (str) => new TextDecoder().decode(base64ToBytes(str));
|
||||
95
core-server/utils/escapecss.js
Normal file
95
core-server/utils/escapecss.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/*\
|
||||
title: $:/core-server/modules/utils/escapecss.js
|
||||
type: application/javascript
|
||||
module-type: utils-node
|
||||
|
||||
Provides CSS.escape() functionality.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
exports.escapeCSS = (function() {
|
||||
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||
|
||||
/* eslint-disable */
|
||||
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
||||
return function(value) {
|
||||
if (arguments.length == 0) {
|
||||
throw new TypeError('`CSS.escape` requires an argument.');
|
||||
}
|
||||
var string = String(value);
|
||||
var length = string.length;
|
||||
var index = -1;
|
||||
var codeUnit;
|
||||
var result = '';
|
||||
var firstCodeUnit = string.charCodeAt(0);
|
||||
while (++index < length) {
|
||||
codeUnit = string.charCodeAt(index);
|
||||
// Note: there’s no need to special-case astral symbols, surrogate
|
||||
// pairs, or lone surrogates.
|
||||
|
||||
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
|
||||
// (U+FFFD).
|
||||
if (codeUnit == 0x0000) {
|
||||
result += '\uFFFD';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
|
||||
// U+007F, […]
|
||||
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
|
||||
// If the character is the first character and is in the range [0-9]
|
||||
// (U+0030 to U+0039), […]
|
||||
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
|
||||
// If the character is the second character and is in the range [0-9]
|
||||
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
|
||||
(
|
||||
index == 1 &&
|
||||
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
|
||||
firstCodeUnit == 0x002D
|
||||
)
|
||||
) {
|
||||
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
|
||||
result += '\\' + codeUnit.toString(16) + ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
// If the character is the first character and is a `-` (U+002D), and
|
||||
// there is no second character, […]
|
||||
index == 0 &&
|
||||
length == 1 &&
|
||||
codeUnit == 0x002D
|
||||
) {
|
||||
result += '\\' + string.charAt(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the character is not handled by one of the above rules and is
|
||||
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
|
||||
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
|
||||
// U+005A), or [a-z] (U+0061 to U+007A), […]
|
||||
if (
|
||||
codeUnit >= 0x0080 ||
|
||||
codeUnit == 0x002D ||
|
||||
codeUnit == 0x005F ||
|
||||
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
|
||||
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
|
||||
codeUnit >= 0x0061 && codeUnit <= 0x007A
|
||||
) {
|
||||
// the character itself
|
||||
result += string.charAt(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, the escaped character.
|
||||
// https://drafts.csswg.org/cssom/#escape-a-character
|
||||
result += '\\' + string.charAt(index);
|
||||
|
||||
}
|
||||
return result;
|
||||
};
|
||||
/* eslint-enable */
|
||||
})();
|
||||
@@ -5,3 +5,4 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
|
||||
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
||||
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
||||
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
|
||||
* [[diff-match-patch-es by antfu|https://github.com/antfu/diff-match-patch-es]]
|
||||
|
||||
@@ -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>>'
|
||||
@@ -1,5 +1,6 @@
|
||||
title: $:/language/
|
||||
|
||||
Alerts: Alerts
|
||||
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
|
||||
BinaryWarning/Prompt: This tiddler contains binary data
|
||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.
|
||||
|
||||
@@ -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 (tagged <<tag "$:/tags/ViewTemplate">>) using a cascade filter and their resulting template for the current tiddler.
|
||||
Advanced/CascadeInfo/Detail/View: View
|
||||
Advanced/CascadeInfo/Detail/ActiveCascadeFilter: Active cascade filter
|
||||
Advanced/CascadeInfo/Detail/Template: Template
|
||||
Fields/Caption: Fields
|
||||
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;
|
||||
@@ -156,8 +156,8 @@ Fix the height of textarea to fit content
|
||||
FramedEngine.prototype.fixHeight = function() {
|
||||
// Make sure styles are updated
|
||||
this.copyStyles();
|
||||
// Adjust height
|
||||
if(this.widget.editTag === "textarea") {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,8 @@ SimpleEngine.prototype.getText = function() {
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
SimpleEngine.prototype.fixHeight = function() {
|
||||
if(this.widget.editTag === "textarea") {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
41
core/modules/filterrunprefixes/let.js
Normal file
41
core/modules/filterrunprefixes/let.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/let.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Assign a value to a variable
|
||||
|
||||
\*/
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.let = function(operationSubFunction,options) {
|
||||
// Return the filter run prefix function
|
||||
return function(results,source,widget) {
|
||||
// Save the result list
|
||||
var resultList = results.toArray();
|
||||
// Clear the results
|
||||
results.clear();
|
||||
// Evaluate the subfunction to get the variable name
|
||||
var subFunctionResults = operationSubFunction(source,widget);
|
||||
if(subFunctionResults.length === 0) {
|
||||
return;
|
||||
}
|
||||
var name = subFunctionResults[0];
|
||||
if(typeof name !== "string" || name.length === 0) {
|
||||
return;
|
||||
}
|
||||
// Assign the result of the subfunction to the variable
|
||||
var variables = {};
|
||||
variables[name] = resultList;
|
||||
// Return the variables
|
||||
return {
|
||||
variables: variables
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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]);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
operator.prefix = filterString.charAt(p++);
|
||||
}
|
||||
// Get the operator name
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
@@ -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);
|
||||
@@ -79,13 +79,17 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
operand.variable = true;
|
||||
nextBracketPos = filterString.indexOf(">",p);
|
||||
break;
|
||||
case "(": // Round brackets
|
||||
operand.multiValuedVariable = true;
|
||||
nextBracketPos = filterString.indexOf(")",p);
|
||||
break;
|
||||
case "/": // regexp brackets
|
||||
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||
rexMatch = rex.exec(filterString.substring(p));
|
||||
if(rexMatch) {
|
||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
nextBracketPos = p + rex.lastIndex - 1;
|
||||
}
|
||||
else {
|
||||
@@ -104,7 +108,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
}
|
||||
operator.operands.push(operand);
|
||||
p = nextBracketPos + 1;
|
||||
}
|
||||
};
|
||||
|
||||
p = nextBracketPos + 1;
|
||||
parseOperand(bracket);
|
||||
@@ -112,7 +116,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
// Check for multiple operands
|
||||
while(filterString.charAt(p) === ",") {
|
||||
p++;
|
||||
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
||||
if(/^[\[\{<\/\(]/.test(filterString.substring(p))) {
|
||||
nextBracketPos = p;
|
||||
p++;
|
||||
parseOperand(filterString.charAt(nextBracketPos));
|
||||
@@ -141,7 +145,15 @@ exports.parseFilter = function(filterString) {
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
// Groups:
|
||||
// 1 - entire filter run prefix
|
||||
// 2 - filter run prefix itself
|
||||
// 3 - filter run prefix suffixes
|
||||
// 4 - opening square bracket following filter run prefix
|
||||
// 5 - double quoted string following filter run prefix
|
||||
// 6 - single quoted string following filter run prefix
|
||||
// 7 - anything except for whitespace and square brackets
|
||||
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -152,38 +164,45 @@ exports.parseFilter = function(filterString) {
|
||||
// Match the start of the operation
|
||||
if(p < filterString.length) {
|
||||
operandRegExp.lastIndex = p;
|
||||
match = operandRegExp.exec(filterString);
|
||||
if(!match || match.index !== p) {
|
||||
throw $tw.language.getString("Error/FilterSyntax");
|
||||
}
|
||||
var operation = {
|
||||
prefix: "",
|
||||
operators: []
|
||||
};
|
||||
if(match[1]) {
|
||||
operation.prefix = match[1];
|
||||
p = p + operation.prefix.length;
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
}
|
||||
if(match[3]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||
}
|
||||
match = operandRegExp.exec(filterString);
|
||||
if(match && match.index === p) {
|
||||
// If there is a filter run prefix
|
||||
if(match[1]) {
|
||||
operation.prefix = match[1];
|
||||
p = p + operation.prefix.length;
|
||||
// Name for named prefixes
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
}
|
||||
// Suffixes for filter run prefix
|
||||
if(match[3]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
// Opening square bracket
|
||||
if(match[4]) {
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
}
|
||||
if(match[4]) { // Opening square bracket
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
// No filter run prefix
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
}
|
||||
// Quoted strings and unquoted title
|
||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||
operation.operators.push(
|
||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||
@@ -209,7 +228,7 @@ exports.getFilterRunPrefixes = function() {
|
||||
$tw.modules.applyMethods("filterrunprefix",this.filterRunPrefixes);
|
||||
}
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
};
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
@@ -251,6 +270,8 @@ exports.compileFilter = function(filterString) {
|
||||
results = [];
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operands = [],
|
||||
multiValueOperands = [],
|
||||
isMultiValueOperand = [],
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
@@ -266,28 +287,46 @@ exports.compileFilter = function(filterString) {
|
||||
if(operand.indirect) {
|
||||
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
operand.multiValue = [operand.value];
|
||||
} else if(operand.variable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||
operand.multiValue = [operand.value];
|
||||
} else if(operand.multiValuedVariable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source});
|
||||
if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) {
|
||||
operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || [];
|
||||
operand.value = operand.multiValue[0] || "";
|
||||
} else {
|
||||
operand.value = "";
|
||||
operand.multiValue = [];
|
||||
}
|
||||
operand.isMultiValueOperand = true;
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
operand.multiValue = [operand.value];
|
||||
}
|
||||
operands.push(operand.value);
|
||||
multiValueOperands.push(operand.multiValue);
|
||||
isMultiValueOperand.push(!!operand.isMultiValueOperand);
|
||||
});
|
||||
|
||||
// Invoke the appropriate filteroperator module
|
||||
results = operatorFunction(accumulator,{
|
||||
operator: operator.operator,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
});
|
||||
operator: operator.operator,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
multiValueOperands: multiValueOperands,
|
||||
isMultiValueOperand: isMultiValueOperand,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
} else {
|
||||
@@ -319,6 +358,8 @@ exports.compileFilter = function(filterString) {
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
@@ -345,7 +386,13 @@ exports.compileFilter = function(filterString) {
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
operationFunction(results,source,widget);
|
||||
var operationResult = operationFunction(results,source,widget);
|
||||
if(operationResult) {
|
||||
if(operationResult.variables) {
|
||||
// If the filter run prefix has returned variables, create a new fake widget with those variables
|
||||
widget = widget.makeFakeWidgetWithVariables(operationResult.variables);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ exports.function = function(source,operator,options) {
|
||||
var functionName = operator.operands[0],
|
||||
params = [],
|
||||
results;
|
||||
$tw.utils.each(operator.operands.slice(1),function(param) {
|
||||
params.push({value: param});
|
||||
$tw.utils.each(operator.multiValueOperands.slice(1),function(paramList) {
|
||||
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||
});
|
||||
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
||||
|
||||
@@ -113,6 +113,22 @@ exports["jsonset"] = function(source,operator,options) {
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsondelete"] = function(source,operator,options) {
|
||||
var indexes = operator.operands,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
// If parsing failed (data equals original title and is a string), return unchanged
|
||||
if(data === title && typeof data === "string") {
|
||||
results.push(title);
|
||||
} else if(data) {
|
||||
data = deleteDataItem(data,indexes);
|
||||
results.push(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
@@ -141,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($tw.utils.isArray(item)) {
|
||||
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);
|
||||
}
|
||||
@@ -178,7 +194,7 @@ function convertDataItemKeysToStrings(item) {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if($tw.utils.isArray(item)) {
|
||||
if(Array.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
@@ -201,7 +217,7 @@ function getDataItemType(data,indexes) {
|
||||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
} else if(Array.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
@@ -213,9 +229,9 @@ function getDataItemType(data,indexes) {
|
||||
function getItemAtIndex(item,index) {
|
||||
if($tw.utils.hop(item,index)) {
|
||||
return item[index];
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
} 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;
|
||||
@@ -223,15 +239,16 @@ function getItemAtIndex(item,index) {
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
Traverse the index chain and return the item at the specified depth.
|
||||
Returns the item at the end of the traversal, or undefined if traversal fails.
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
function traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
|
||||
for(var i = 0; i < stopIndex; i++) {
|
||||
if(item !== undefined) {
|
||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||
item = getItemAtIndex(item,indexes[i]);
|
||||
@@ -243,6 +260,13 @@ function getDataItem(data,indexes) {
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
function getDataItem(data,indexes) {
|
||||
return traverseIndexChain(data,indexes,false);
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
||||
*/
|
||||
@@ -255,20 +279,17 @@ function setDataItem(data,indexes,value) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return value;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain
|
||||
var current = data;
|
||||
for(var i = 0; i < indexes.length - 1; i++) {
|
||||
current = getItemAtIndex(current,indexes[i]);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Add the value to the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if($tw.utils.isArray(current)) {
|
||||
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") {
|
||||
@@ -276,3 +297,32 @@ function setDataItem(data,indexes,value) {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
|
||||
*/
|
||||
function deleteDataItem(data,indexes) {
|
||||
// Check for the root item - don't delete the root
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined || current === null) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Delete the item at the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current) && current !== null) {
|
||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length; };
|
||||
// Check if index is valid before splicing
|
||||
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||
current.splice(lastIndex,1);
|
||||
}
|
||||
} else if(typeof current === "object" && current !== null) {
|
||||
delete current[lastIndex];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -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.operand || "title",operator.prefix === "!",false,false);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortan = function(source, operator, options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
|
||||
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]);
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
|
||||
operand = (operator.operand || ""),
|
||||
fnCalc;
|
||||
if(suffix === "prefix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];};
|
||||
} else if(suffix === "suffix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];};
|
||||
} else {
|
||||
if(operand === "") {
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];}
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];};
|
||||
} else {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];};
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
@@ -71,107 +71,53 @@ exports.join = makeStringReducingOperator(
|
||||
},null
|
||||
);
|
||||
|
||||
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
|
||||
exports.levenshtein = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
diffs = dmpObject.diff_main(a,b);
|
||||
return [dmpObject.diff_levenshtein(diffs) + ""];
|
||||
const diffs = dmp.diffMain(a,b);
|
||||
return [dmp.diffLevenshtein(diffs).toString()];
|
||||
}
|
||||
);
|
||||
|
||||
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
function diffLineWordMode(text1,text2,mode) {
|
||||
var dmpObject = new dmp.diff_match_patch();
|
||||
var a = diffPartsToChars(text1,text2,mode);
|
||||
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
|
||||
var lineText1 = a.chars1;
|
||||
var lineText2 = a.chars2;
|
||||
var lineArray = a.lineArray;
|
||||
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
||||
dmpObject.diff_charsToLines_(diffs,lineArray);
|
||||
var diffs = dmp.diffMain(lineText1,lineText2,false);
|
||||
dmp.diffCharsToLines(diffs,lineArray);
|
||||
return diffs;
|
||||
}
|
||||
|
||||
function diffPartsToChars(text1,text2,mode) {
|
||||
var lineArray = [];
|
||||
var lineHash = {};
|
||||
lineArray[0] = '';
|
||||
|
||||
function diff_linesToPartsMunge_(text,mode) {
|
||||
var chars = '';
|
||||
var lineStart = 0;
|
||||
var lineEnd = -1;
|
||||
var lineArrayLength = lineArray.length,
|
||||
regexpResult;
|
||||
var searchRegexp = /\W+/g;
|
||||
while(lineEnd < text.length - 1) {
|
||||
if(mode === "words") {
|
||||
regexpResult = searchRegexp.exec(text);
|
||||
lineEnd = searchRegexp.lastIndex;
|
||||
if(regexpResult === null) {
|
||||
lineEnd = text.length;
|
||||
}
|
||||
lineEnd = --lineEnd;
|
||||
} else {
|
||||
lineEnd = text.indexOf('\n', lineStart);
|
||||
if(lineEnd == -1) {
|
||||
lineEnd = text.length - 1;
|
||||
}
|
||||
}
|
||||
var line = text.substring(lineStart, lineEnd + 1);
|
||||
|
||||
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
||||
chars += String.fromCharCode(lineHash[line]);
|
||||
} else {
|
||||
if(lineArrayLength == maxLines) {
|
||||
line = text.substring(lineStart);
|
||||
lineEnd = text.length;
|
||||
}
|
||||
chars += String.fromCharCode(lineArrayLength);
|
||||
lineHash[line] = lineArrayLength;
|
||||
lineArray[lineArrayLength++] = line;
|
||||
}
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
var maxLines = 40000;
|
||||
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||
maxLines = 65535;
|
||||
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
||||
};
|
||||
|
||||
exports.makepatches = function(source,operator,options) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
suffix = operator.suffix || "",
|
||||
var suffix = operator.suffix || "",
|
||||
result = [];
|
||||
|
||||
source(function(tiddler,title) {
|
||||
var diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmpObject.patch_make(title,diffs);
|
||||
} else {
|
||||
patches = dmpObject.patch_make(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
||||
});
|
||||
source(function(tiddler,title) {
|
||||
let diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmp.patchMake(title,diffs);
|
||||
} else {
|
||||
patches = dmp.patchMake(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.applypatches = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
patches;
|
||||
let patches;
|
||||
try {
|
||||
patches = dmpObject.patch_fromText(b);
|
||||
patches = dmp.patchFromText(b);
|
||||
} catch(e) {
|
||||
}
|
||||
if(patches) {
|
||||
return [dmpObject.patch_apply(patches,a)[0]];
|
||||
return [dmp.patchApply(patches,a)[0]];
|
||||
} else {
|
||||
return [a];
|
||||
}
|
||||
@@ -279,7 +225,7 @@ exports.pad = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
exports.charcode = function(source,operator,options) {
|
||||
var chars = [];
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -16,12 +16,13 @@ exports.title = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
if(tiddler && tiddler.fields.title !== operator.operand) {
|
||||
var titleList = operator.multiValueOperands[0] || [];
|
||||
if(tiddler && titleList.indexOf(tiddler.fields.title) === -1) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
results.push(operator.operand);
|
||||
Array.prototype.push.apply(results,operator.multiValueOperands[0]);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -20,8 +20,8 @@ exports["[unknown]"] = function(source,operator,options) {
|
||||
// Check for a user defined filter operator
|
||||
if(operator.operator.indexOf(".") !== -1) {
|
||||
var params = [];
|
||||
$tw.utils.each(operator.operands,function(param) {
|
||||
params.push({value: param});
|
||||
$tw.utils.each(operator.multiValueOperands,function(paramList) {
|
||||
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||
});
|
||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
|
||||
if(variableInfo && variableInfo.srcVariable) {
|
||||
|
||||
@@ -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)
|
||||
]
|
||||
];
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -266,7 +266,7 @@ KeyboardManager.prototype.getPrintableShortcuts = function(keyInfoArray) {
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
KeyboardManager.prototype.checkKeyDescriptor = function(event,keyInfo) {
|
||||
return keyInfo &&
|
||||
@@ -293,15 +293,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 +371,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);
|
||||
|
||||
@@ -46,24 +46,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 "";
|
||||
|
||||
@@ -13,13 +13,13 @@ The audio parser parses an audio tiddler into an embeddable HTML element
|
||||
|
||||
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;
|
||||
|
||||
@@ -11,10 +11,13 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
|
||||
|
||||
var CsvParser = function(type,text,options) {
|
||||
// Special handler for tab-delimited files
|
||||
if (type === 'text/tab-delimited-values' && !options.separator) {
|
||||
if(
|
||||
!options.separator &&
|
||||
(type === "text/tab-delimited-values" || type === "text/tab-separated-values")
|
||||
) {
|
||||
options.separator = "\t";
|
||||
}
|
||||
|
||||
|
||||
// Table framework
|
||||
this.tree = [{
|
||||
"type": "scrollable", "children": [{
|
||||
@@ -32,7 +35,7 @@ var CsvParser = function(type,text,options) {
|
||||
$tw.utils.each(lines, function(columns) {
|
||||
maxColumns = Math.max(columns.length, maxColumns);
|
||||
});
|
||||
|
||||
|
||||
for(var line=0; line<lines.length; line++) {
|
||||
var columns = lines[line];
|
||||
var row = {
|
||||
@@ -42,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] || ""
|
||||
}]
|
||||
});
|
||||
}
|
||||
@@ -55,3 +58,4 @@ var CsvParser = function(type,text,options) {
|
||||
|
||||
exports["text/csv"] = CsvParser;
|
||||
exports["text/tab-delimited-values"] = CsvParser;
|
||||
exports["text/tab-separated-values"] = CsvParser;
|
||||
|
||||
@@ -11,17 +11,16 @@ The image parser parses an image into an embeddable HTML element
|
||||
|
||||
var ImageParser = function(type,text,options) {
|
||||
var element = {
|
||||
type: "element",
|
||||
tag: "img",
|
||||
attributes: {}
|
||||
};
|
||||
type: "image",
|
||||
attributes: {}
|
||||
};
|
||||
if(options._canonical_uri) {
|
||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||
element.attributes.source = {type: "string", value: options._canonical_uri};
|
||||
} else if(text) {
|
||||
if(type === "image/svg+xml" || type === ".svg") {
|
||||
element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||
element.attributes.source = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||
} else {
|
||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
element.attributes.source = {type: "string", value: "data:" + type + ";base64," + text};
|
||||
}
|
||||
}
|
||||
this.tree = [element];
|
||||
|
||||
@@ -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]*?)"""|"([^"]*)")|(?:'([^']*)')|\[\[((?:[^\]]|\](?!\]))*)\]\]/g;
|
||||
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,201 @@ 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>"'=:]+)/g;
|
||||
// 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 >>
|
||||
if(!$tw.utils.parseWhiteSpace(source,pos) && !(source.charAt(pos) === ">" && source.charAt(pos + 1) === ">") ) {
|
||||
return null;
|
||||
}
|
||||
// Process attributes
|
||||
pos = $tw.utils.parseMacroParametersAsAttributes(node,source,pos);
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double closing angle bracket
|
||||
token = $tw.utils.parseTokenString(source,pos,">>");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
node.end = token.end;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Look for an MVV (multi-valued variable) reference as a transclusion, i.e. ((varname)) or ((varname params))
|
||||
Returns null if not found, or a parse tree node of type "transclude" with isMVV: true
|
||||
*/
|
||||
exports.parseMVVReferenceAsTransclusion = function(source,pos) {
|
||||
var node = {
|
||||
type: "transclude",
|
||||
isMVV: true,
|
||||
start: pos,
|
||||
attributes: {},
|
||||
orderedAttributes: []
|
||||
};
|
||||
// Define our regexps
|
||||
var reVarName = /([^\s>"'=:)]+)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double opening parenthesis
|
||||
var token = $tw.utils.parseTokenString(source,pos,"((");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
pos = token.end;
|
||||
// Get the variable name
|
||||
token = $tw.utils.parseTokenRegExp(source,pos,reVarName);
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
$tw.utils.addAttributeToParseTreeNode(node,"$variable",token.match[1]);
|
||||
pos = token.end;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a double closing parenthesis
|
||||
token = $tw.utils.parseTokenString(source,pos,"))");
|
||||
if(!token) {
|
||||
return null;
|
||||
}
|
||||
node.end = token.end;
|
||||
return node;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse macro parameters as attributes. Returns the position after the last attribute
|
||||
*/
|
||||
exports.parseMacroParametersAsAttributes = function(node,source,pos) {
|
||||
var position = 0,
|
||||
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
|
||||
while(attribute) {
|
||||
if(!attribute.name) {
|
||||
attribute.name = (position++) + "";
|
||||
attribute.isPositional = true;
|
||||
}
|
||||
node.orderedAttributes.push(attribute);
|
||||
node.attributes[attribute.name] = attribute;
|
||||
pos = attribute.end;
|
||||
// Get the next attribute
|
||||
attribute = $tw.utils.parseMacroParameterAsAttribute(source,pos);
|
||||
}
|
||||
node.end = pos;
|
||||
return pos;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse a macro parameter as an attribute. Returns null if not found, otherwise returns {name:, type: "filtered|string|indirect|macro", value|filter|textReference:, start:, end:,}, with the name being optional
|
||||
*/
|
||||
exports.parseMacroParameterAsAttribute = function(source,pos) {
|
||||
var node = {
|
||||
start: pos
|
||||
};
|
||||
// Define our regexps
|
||||
var reAttributeName = /([^\/\s>"'`=:]+)/g,
|
||||
reUnquotedAttribute = /((?:(?:>(?!>))|[^\s>"'])+)/g,
|
||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
||||
reIndirectValue = /\{\{([^\}]+)\}\}/g,
|
||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Get the attribute name and the separator token
|
||||
var nameToken = $tw.utils.parseTokenRegExp(source,pos,reAttributeName),
|
||||
namePos = nameToken && $tw.utils.skipWhiteSpace(source,nameToken.end),
|
||||
separatorToken = nameToken && $tw.utils.parseTokenRegExp(source,namePos,/=|:/g),
|
||||
isNewStyleSeparator = false; // If there is no separator then we don't allow new style values
|
||||
// If we have a name and a separator then we have a named attribute
|
||||
if(nameToken && separatorToken) {
|
||||
node.name = nameToken.match[1];
|
||||
// key value separator is `=` or `:`
|
||||
node.assignmentOperator = separatorToken.match[0];
|
||||
pos = separatorToken.end;
|
||||
isNewStyleSeparator = (node.assignmentOperator === "=");
|
||||
}
|
||||
// Skip whitespace
|
||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||
// Look for a string literal
|
||||
var stringLiteral = $tw.utils.parseStringLiteral(source,pos);
|
||||
if(stringLiteral) {
|
||||
pos = stringLiteral.end;
|
||||
node.type = "string";
|
||||
node.value = stringLiteral.value;
|
||||
// Mark the value as having been quoted in the source
|
||||
node.quoted = true;
|
||||
} else {
|
||||
// Look for a filtered value
|
||||
var filteredValue = $tw.utils.parseTokenRegExp(source,pos,reFilteredValue);
|
||||
if(filteredValue && isNewStyleSeparator) {
|
||||
pos = filteredValue.end;
|
||||
node.type = "filtered";
|
||||
node.filter = filteredValue.match[1];
|
||||
} else {
|
||||
// Look for an indirect value
|
||||
var indirectValue = $tw.utils.parseTokenRegExp(source,pos,reIndirectValue);
|
||||
if(indirectValue && isNewStyleSeparator) {
|
||||
pos = indirectValue.end;
|
||||
node.type = "indirect";
|
||||
node.textReference = indirectValue.match[1];
|
||||
} else {
|
||||
// Look for a macro invocation value
|
||||
var macroInvocation = $tw.utils.parseMacroInvocationAsTransclusion(source,pos);
|
||||
if(macroInvocation && isNewStyleSeparator) {
|
||||
pos = macroInvocation.end;
|
||||
node.type = "macro";
|
||||
node.value = macroInvocation;
|
||||
} else {
|
||||
// Look for an MVV reference value
|
||||
var mvvReference = $tw.utils.parseMVVReferenceAsTransclusion(source,pos);
|
||||
if(mvvReference && isNewStyleSeparator) {
|
||||
pos = mvvReference.end;
|
||||
node.type = "macro";
|
||||
node.value = mvvReference;
|
||||
node.isMVV = true;
|
||||
} else {
|
||||
var substitutedValue = $tw.utils.parseTokenRegExp(source,pos,reSubstitutedValue);
|
||||
if(substitutedValue && isNewStyleSeparator) {
|
||||
pos = substitutedValue.end;
|
||||
node.type = "substituted";
|
||||
node.rawValue = substitutedValue.match[1] || substitutedValue.match[2];
|
||||
} else {
|
||||
// Look for a unquoted value
|
||||
var unquotedValue = $tw.utils.parseTokenRegExp(source,pos,reUnquotedAttribute);
|
||||
if(unquotedValue) {
|
||||
pos = unquotedValue.end;
|
||||
node.type = "string";
|
||||
node.value = unquotedValue.match[1];
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bail if we don't have a value
|
||||
if(!node.type) {
|
||||
return null;
|
||||
}
|
||||
// Update the end position
|
||||
node.end = pos;
|
||||
return node;
|
||||
};
|
||||
|
||||
@@ -296,7 +477,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 +527,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 +548,16 @@ 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 {
|
||||
node.type = "string";
|
||||
node.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +565,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";
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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}
|
||||
]
|
||||
}];
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -32,10 +32,10 @@ function SaverHandler(options) {
|
||||
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
||||
// Count of changes that have not yet been saved
|
||||
var filteredChanges = self.filterFn.call(self.wiki,function(iterator) {
|
||||
$tw.utils.each(self.preloadDirty,function(title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
iterator(tiddler,title);
|
||||
});
|
||||
$tw.utils.each(self.preloadDirty,function(title) {
|
||||
var tiddler = self.wiki.getTiddler(title);
|
||||
iterator(tiddler,title);
|
||||
});
|
||||
});
|
||||
this.numChanges = filteredChanges.length;
|
||||
// Listen out for changes to tiddlers
|
||||
|
||||
@@ -15,27 +15,27 @@ var AndTidWiki = function(wiki) {
|
||||
|
||||
AndTidWiki.prototype.save = function(text,method,callback,options) {
|
||||
var filename = options && options.variables ? options.variables.filename : null;
|
||||
if (method === "download") {
|
||||
if(method === "download") {
|
||||
// Support download
|
||||
if (window.twi.saveDownload) {
|
||||
if(window.twi.saveDownload) {
|
||||
try {
|
||||
window.twi.saveDownload(text,filename);
|
||||
} catch(err) {
|
||||
if (err.message === "Method not found") {
|
||||
if(err.message === "Method not found") {
|
||||
window.twi.saveDownload(text);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var link = document.createElement("a");
|
||||
link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
|
||||
if (filename) {
|
||||
link.setAttribute("download",filename);
|
||||
if(filename) {
|
||||
link.setAttribute("download",filename);
|
||||
}
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
} else if (window.twi.saveWiki) {
|
||||
} else if(window.twi.saveWiki) {
|
||||
// Direct save in Tiddloid
|
||||
window.twi.saveWiki(text);
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user