mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-02-20 08:59:50 +00:00
Compare commits
18 Commits
remove-cor
...
offload-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c333d8d2e | ||
|
|
948c040554 | ||
|
|
5f104f129f | ||
|
|
98f850609d | ||
|
|
3f5c2bfba3 | ||
|
|
ee16e48a43 | ||
|
|
a989079201 | ||
|
|
12934caaa8 | ||
|
|
f70e1b8a46 | ||
|
|
52ee685572 | ||
|
|
c684f885ce | ||
|
|
c6c83bc18b | ||
|
|
b80213128f | ||
|
|
3faf503073 | ||
|
|
2ea6153a74 | ||
|
|
1752eba1e8 | ||
|
|
98dc094593 | ||
|
|
fc4190bb25 |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,4 +0,0 @@
|
||||
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
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,62 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[Report] "
|
||||
type: report
|
||||
|
||||
---
|
||||
|
||||
<!-- Remove elements, that you do not need -->
|
||||
<!-- Add screenshots where needed -->
|
||||
|
||||
**Problem Description**
|
||||
<!-- Describe your problem: A clear and concise description of what your problem is -->
|
||||
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. At https://tiddlywiki.com
|
||||
2. Click on ...
|
||||
3. Scroll down to ...
|
||||
4. See ...
|
||||
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
As a user,
|
||||
<!-- As a developer, -->
|
||||
I would expect ...
|
||||
|
||||
|
||||
**TiddlyWiki Configuration**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
|
||||
|
||||
<!-- Your report comes here -->
|
||||
<!-- or -->
|
||||
<!-- Add it manually -->
|
||||
|
||||
- Version: <!-- e.g. v5.3.8 -->
|
||||
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
|
||||
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
|
||||
|
||||
|
||||
**Desktop**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- OS: <!-- e.g. iOS -->
|
||||
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
|
||||
|
||||
**Smartphone**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Device: <!-- e.g. iPhone6 -->
|
||||
- OS: <!-- e.g. iOS8.1 -->
|
||||
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
|
||||
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
||||
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
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,23 +4,17 @@ about: Suggest an idea for TiddlyWiki 5
|
||||
title: "[IDEA]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
type: idea
|
||||
|
||||
---
|
||||
|
||||
**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 [...]
|
||||
**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 [...]
|
||||
|
||||
**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.
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
TW5_BUILD_OUTPUT: "./output"
|
||||
TW5_BUILD_ARCHIVE: "./output"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
|
||||
40
.github/workflows/eslint.yml
vendored
40
.github/workflows/eslint.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: ESLint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: lint-${{ github.event.pull_request.number || github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# Needed for GitHub Checks API
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --include=dev
|
||||
|
||||
- name: Run ESLint with reviewdog (GitHub Checks)
|
||||
uses: reviewdog/action-eslint@v1
|
||||
with:
|
||||
eslint_flags: '.'
|
||||
reporter: github-pr-check
|
||||
fail_level: error
|
||||
level: error
|
||||
tool_name: ESLint PR code
|
||||
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@v6
|
||||
uses: TiddlyWiki/cerebrus@v4
|
||||
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@v6
|
||||
uses: TiddlyWiki/cerebrus@v4
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
repo: ${{ github.repository }}
|
||||
|
||||
18
.github/workflows/pr-path-validation.yml
vendored
Normal file
18
.github/workflows/pr-path-validation.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
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
37
.github/workflows/pr-validation.yml
vendored
@@ -1,37 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -73,8 +73,10 @@ rm $TW5_BUILD_OUTPUT/dev/static/*
|
||||
|
||||
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
|
||||
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
|
||||
|
||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||
|
||||
@@ -120,6 +122,7 @@ 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 \
|
||||
@@ -298,6 +301,26 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
|
||||
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tahoelafs \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
|
||||
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/d3demo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
|
||||
144
boot/boot.js
144
boot/boot.js
@@ -8,8 +8,6 @@ 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 */
|
||||
@@ -46,8 +44,12 @@ $tw.utils.hop = function(object,property) {
|
||||
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
|
||||
};
|
||||
|
||||
/** @deprecated Use Array.isArray instead */
|
||||
$tw.utils.isArray = value => Array.isArray(value);
|
||||
/*
|
||||
Determine if a value is an array
|
||||
*/
|
||||
$tw.utils.isArray = function(value) {
|
||||
return Object.prototype.toString.call(value) == "[object Array]";
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
@@ -126,22 +128,35 @@ $tw.utils.pushTop = function(array,value) {
|
||||
return array;
|
||||
};
|
||||
|
||||
/** @deprecated Use instanceof Date instead */
|
||||
$tw.utils.isDate = value => value instanceof Date;
|
||||
/*
|
||||
Determine if a value is a date
|
||||
*/
|
||||
$tw.utils.isDate = function(value) {
|
||||
return Object.prototype.toString.call(value) === "[object Date]";
|
||||
};
|
||||
|
||||
/** @deprecated Use array iterative methods instead */
|
||||
/*
|
||||
Iterate through all the own properties of an object or array. Callback is invoked with (element,title,object)
|
||||
*/
|
||||
$tw.utils.each = function(object,callback) {
|
||||
var next,f,length;
|
||||
if(object) {
|
||||
if(Array.isArray(object)) {
|
||||
object.every((element,index,array) => {
|
||||
const next = callback(element,index,array);
|
||||
return next !== false;
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object.entries(object).every(entry => {
|
||||
const next = callback(entry[1], entry[0], object);
|
||||
return next !== false;
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -320,26 +335,28 @@ $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() {
|
||||
const href = window.location.href,
|
||||
idx = href.indexOf("#");
|
||||
|
||||
var href = window.location.href;
|
||||
var idx = href.indexOf('#');
|
||||
if(idx === -1) {
|
||||
return "#";
|
||||
}
|
||||
|
||||
const afterHash = href.substring(idx + 1);
|
||||
if(afterHash.startsWith("#") || afterHash.startsWith("%23")) {
|
||||
} else if(href.substr(idx + 1,1) === "#" || href.substr(idx + 1,3) === "%23") {
|
||||
// Special case: ignore location hash if it itself starts with a #
|
||||
return "#";
|
||||
} else {
|
||||
return href.substring(idx);
|
||||
}
|
||||
return href.substring(idx);
|
||||
};
|
||||
|
||||
|
||||
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
|
||||
$tw.utils.pad = function(value,length = 2) {
|
||||
const s = value.toString();
|
||||
return s.padStart(length, "0");
|
||||
/*
|
||||
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;
|
||||
};
|
||||
|
||||
// Convert a date into UTC YYYYMMDDHHMMSSmmm format
|
||||
@@ -613,7 +630,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||
// Compile the code into a function
|
||||
var fn;
|
||||
if($tw.browser) {
|
||||
fn = Function("return " + code + "\n\n//# sourceURL=" + filename)(); // See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
|
||||
} else {
|
||||
if(sandbox){
|
||||
fn = vm.runInContext(code,sandbox,filename)
|
||||
@@ -624,7 +641,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||
// Call the function and return the exports
|
||||
return fn.apply(null,contextValues);
|
||||
};
|
||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||
/*
|
||||
Run code in a sandbox with only the specified context variables in scope
|
||||
*/
|
||||
@@ -782,13 +799,12 @@ the password, and to encrypt/decrypt a block of text
|
||||
$tw.utils.Crypto = function() {
|
||||
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
||||
currentPassword = null,
|
||||
callSjcl = function(method,inputText,password,options) {
|
||||
options = options || {};
|
||||
callSjcl = function(method,inputText,password) {
|
||||
password = password || currentPassword;
|
||||
var outputText;
|
||||
try {
|
||||
if(password) {
|
||||
outputText = sjcl[method](password,inputText,options);
|
||||
outputText = sjcl[method](password,inputText);
|
||||
}
|
||||
} catch(ex) {
|
||||
console.log("Crypto error:" + ex);
|
||||
@@ -814,8 +830,7 @@ $tw.utils.Crypto = 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"});
|
||||
return callSjcl("encrypt",text,password);
|
||||
};
|
||||
this.decrypt = function(text,password) {
|
||||
return callSjcl("decrypt",text,password);
|
||||
@@ -1515,8 +1530,7 @@ Define all modules stored in ordinary tiddlers
|
||||
*/
|
||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||
this.each(function(tiddler,title) {
|
||||
// Modules in draft tiddlers are disabled
|
||||
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
|
||||
if(tiddler.hasField("module-type")) {
|
||||
switch(tiddler.fields.type) {
|
||||
case "application/javascript":
|
||||
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||
@@ -1543,11 +1557,6 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
||||
this.eachShadow(function(tiddler,title) {
|
||||
// Don't define the module if it is overidden by an ordinary tiddler
|
||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||
if(tiddler.hasField("draft.of")) {
|
||||
// Report a fundamental problem
|
||||
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
|
||||
return;
|
||||
}
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
@@ -1896,7 +1905,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
||||
fileSize = fs.statSync(filepath).size,
|
||||
data;
|
||||
if(fileSize > $tw.config.maxEditFileSize) {
|
||||
data = "File " + filepath + " not loaded because it is too large";
|
||||
data = "File " + filepath + "not loaded because it is too large";
|
||||
console.log("Warning: " + data);
|
||||
ext = ".txt";
|
||||
} else {
|
||||
@@ -1967,41 +1976,22 @@ filepath: pathname of the directory containing the specification file
|
||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var tiddlers = [];
|
||||
// Read the specification
|
||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"), function(e) {
|
||||
console.log("Warning: tiddlywiki.files in " + filepath + " invalid: " + e.message);
|
||||
return {};
|
||||
});
|
||||
|
||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
pathname = path.resolve(filepath,filename),
|
||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||
fileTooLarge = false,
|
||||
text, fileTiddlers;
|
||||
|
||||
if("_canonical_uri" in fields) {
|
||||
text = "";
|
||||
} else if(fs.statSync(pathname).size > $tw.config.maxEditFileSize) {
|
||||
var msg = "File " + pathname + " not loaded because it is too large";
|
||||
console.log("Warning: " + msg);
|
||||
fileTooLarge = true;
|
||||
text = isTiddlerFile ? msg : "";
|
||||
} else {
|
||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8");
|
||||
}
|
||||
|
||||
fileTiddlers;
|
||||
if(isTiddlerFile) {
|
||||
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
|
||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
||||
} else {
|
||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||
}
|
||||
var combinedFields = $tw.utils.extend({},fields,metadata);
|
||||
if(fileTooLarge && isTiddlerFile) {
|
||||
delete combinedFields.type; // type altered
|
||||
}
|
||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||
@@ -2076,7 +2066,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
} else if(tidInfo.suffix) {
|
||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||
}
|
||||
tidInfo.fields = tidInfo.fields || {};
|
||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||
});
|
||||
// Process any listed directories
|
||||
@@ -2098,7 +2087,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var thisPath = path.relative(filepath, files[t]),
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
dirSpec.fields = dirSpec.fields || {};
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||
}
|
||||
}
|
||||
@@ -2561,10 +2549,10 @@ $tw.boot.execStartup = function(options){
|
||||
if($tw.safeMode) {
|
||||
$tw.wiki.processSafeMode();
|
||||
}
|
||||
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
|
||||
// Tiddlers should appear last so that they may overwrite shadows during module registration
|
||||
$tw.wiki.defineShadowModules();
|
||||
// Register typed modules from the tiddlers we've just loaded
|
||||
$tw.wiki.defineTiddlerModules();
|
||||
// And any modules within plugins
|
||||
$tw.wiki.defineShadowModules();
|
||||
// Make sure the crypto state tiddler is up to date
|
||||
if($tw.crypto) {
|
||||
$tw.crypto.updateCryptoStateTiddler();
|
||||
@@ -2633,13 +2621,11 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
||||
$tw.boot.log(s.join(" "));
|
||||
// Execute task
|
||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||
const thenable = task.startup();
|
||||
if(thenable && typeof thenable.then === "function"){
|
||||
thenable.then(asyncTaskCallback);
|
||||
return true;
|
||||
} else {
|
||||
return asyncTaskCallback();
|
||||
task.startup();
|
||||
if(task.name) {
|
||||
$tw.boot.executedStartupModules[task.name] = true;
|
||||
}
|
||||
return $tw.boot.executeNextStartupTask(callback);
|
||||
} else {
|
||||
task.startup(asyncTaskCallback);
|
||||
return true;
|
||||
@@ -2784,8 +2770,6 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) !== "undefined") {
|
||||
exports.TiddlyWiki = _boot;
|
||||
} else {
|
||||
|
||||
@@ -12,8 +12,6 @@ See Boot.js for further details of the boot process.
|
||||
|
||||
\*/
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
|
||||
var _bootprefix = (function($tw) {
|
||||
|
||||
"use strict";
|
||||
@@ -116,8 +114,6 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) === "undefined") {
|
||||
// Set up $tw global for the browser
|
||||
window.$tw = _bootprefix(window.$tw);
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
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.
|
||||
@@ -6,7 +6,6 @@ talk.tiddlywiki.org: jeremyruston
|
||||
github: Jermolene
|
||||
linkedin: www.linkedin.com/in/jermy
|
||||
flickr: www.flickr.com/photos/jermy/
|
||||
bluesky: https://bsky.app/profile/jermolene.bsky.social
|
||||
homepage: jermolene.com
|
||||
email: jeremy@jermolene.com
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAtAAEBAAMAAAAAAAAAAAAAAAAHBgIEBQEBAQEBAAAAAAAAAAAAAAAAAgQBBf/aAAwDAQACEAMQAAAANF4uTuPRhD2nBLnUiJvKM0DtMKy//8QAKxAAAgIBAwMDAQkAAAAAAAAAAQIDBBEABRITITEiMkFxFEJRUmFicoGR/9oACAEBAAE/AInTA6gUGP4ZOQbW1bPsmyUq1q+gmvFPUzZPDkPamtwqU75ks04JakroVcg5RwRjg66NUx25KbzqJYyMngfqSuq0M3NZYIebJIvZozIvI/iNPcp/aalSdJXsS4VcKeIzlvU3jVTcYLNiaGISrjkhWQYDfQ63pYAzCDBsOiu7Dsx4EHH6r2w2ttimjd2IsNErhhJHKI04/uzqxuCxpBYVVWKSHqwMyMSQ33SB7dUJFmlkMYRgnqZgCMf7rf8AeEt3A9YOhjXAb2k8u7dtT1RZeOtXmYxiOPj4ZWY/lb51skqUNnNW/wBNzC7IpB6gQeeB/jq/fqGOaLbowuYn5MAQOw8LjW5Vmeo0qIsqYLLKjHIZmwv9fB1//8QAHxEAAQMEAwEAAAAAAAAAAAAAEQABAgMSIWExMkFR/9oACAECAQE/AD9iTy2lJmHUB8BVKM4SNSOj46a29saX/8QAHREAAgICAwEAAAAAAAAAAAAAAQIAAwQRITGBkf/aAAgBAwEBPwDHpFpJZtamVSiBWT2Yt7hmCDsb+TKtsKqpGg3M/9k=
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
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.
|
||||
@@ -1,25 +0,0 @@
|
||||
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
|
||||
@@ -1,19 +0,0 @@
|
||||
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 @@
|
||||
created: 20250909171928024
|
||||
modified: 20251110133437795
|
||||
tags: Community/Team
|
||||
team: @MotovunJack
|
||||
title: Infrastructure Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
team: @MotovunJack
|
||||
|
||||
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,4 +12,3 @@ The infrastructure includes:
|
||||
* github.com/TiddlyWiki
|
||||
* tiddlywiki.com DNS
|
||||
* Netlify account for PR previews
|
||||
* edit.tiddlywiki.com
|
||||
6
community/project/teams/Newsletter Team.tid
Normal file
6
community/project/teams/Newsletter Team.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
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.
|
||||
@@ -1,11 +0,0 @@
|
||||
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.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
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]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
|
||||
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Infrastructure Team]] [[Succession Team]]
|
||||
|
||||
|
||||
@@ -99,18 +99,16 @@ Commander.prototype.executeNextCommand = function() {
|
||||
}
|
||||
}
|
||||
if(command.info.synchronous) {
|
||||
// Synchronous command (await thenables)
|
||||
// Synchronous command
|
||||
c = new command.Command(params,this);
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||
} else if(err) {
|
||||
if(err) {
|
||||
this.callback(err);
|
||||
} else {
|
||||
this.executeNextCommand();
|
||||
}
|
||||
} else {
|
||||
// Asynchronous command (await thenables)
|
||||
// Asynchronous command
|
||||
c = new command.Command(params,this,function(err) {
|
||||
if(err) {
|
||||
self.callback(err);
|
||||
@@ -119,9 +117,7 @@ Commander.prototype.executeNextCommand = function() {
|
||||
}
|
||||
});
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { if(e) this.callback(e); });
|
||||
} else if(err) {
|
||||
if(err) {
|
||||
this.callback(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,3 @@ This plugin contains TiddlyWiki's core components that are only needed on the se
|
||||
|
||||
* Commands
|
||||
* HTTP server code
|
||||
* Utility functions for server
|
||||
|
||||
@@ -8,14 +8,10 @@ DELETE /recipes/default/tiddlers/:title
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["DELETE"];
|
||||
exports.method = "DELETE";
|
||||
|
||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
state.wiki.deleteTiddler(title);
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /favicon.ico
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/favicon.ico$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||
|
||||
@@ -8,66 +8,35 @@ GET /files/:filepath
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/files\/(.+)$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var path = require("path"),
|
||||
fs = require("fs"),
|
||||
util = require("util"),
|
||||
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||
filename = path.resolve(baseFilename,suppliedFilename),
|
||||
extension = path.extname(filename);
|
||||
// Check that the filename is inside the wiki files folder
|
||||
if(path.relative(baseFilename,filename).indexOf("..") === 0) {
|
||||
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
}
|
||||
fs.stat(filename, function(err, stats) {
|
||||
if(err) {
|
||||
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
} else {
|
||||
var type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream"),
|
||||
responseHeaders = {
|
||||
"Content-Type": type,
|
||||
"Accept-Ranges": "bytes"
|
||||
};
|
||||
var rangeHeader = request.headers.range,
|
||||
stream;
|
||||
if(rangeHeader) {
|
||||
// Handle range requests
|
||||
var parts = rangeHeader.replace(/bytes=/, "").split("-"),
|
||||
start = parseInt(parts[0], 10),
|
||||
end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
|
||||
// Validate start and end
|
||||
if(isNaN(start) || isNaN(end) || start < 0 || end < start || end >= stats.size) {
|
||||
responseHeaders["Content-Range"] = "bytes */" + stats.size;
|
||||
return response.writeHead(416, responseHeaders).end();
|
||||
}
|
||||
var chunksize = (end - start) + 1;
|
||||
responseHeaders["Content-Range"] = "bytes " + start + "-" + end + "/" + stats.size;
|
||||
responseHeaders["Content-Length"] = chunksize;
|
||||
response.writeHead(206, responseHeaders);
|
||||
stream = fs.createReadStream(filename, {start: start, end: end});
|
||||
if(path.relative(baseFilename,filename).indexOf("..") !== 0) {
|
||||
// Send the file
|
||||
fs.readFile(filename,function(err,content) {
|
||||
var status,content,type = "text/plain";
|
||||
if(err) {
|
||||
console.log("Error accessing file " + filename + ": " + err.toString());
|
||||
status = 404;
|
||||
content = "File '" + suppliedFilename + "' not found";
|
||||
} else {
|
||||
responseHeaders["Content-Length"] = stats.size;
|
||||
response.writeHead(200, responseHeaders);
|
||||
stream = fs.createReadStream(filename);
|
||||
status = 200;
|
||||
content = content;
|
||||
type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream");
|
||||
}
|
||||
// Common stream error handling
|
||||
stream.on("error", function(err) {
|
||||
if(!response.headersSent) {
|
||||
response.writeHead(500, {"Content-Type": "text/plain"});
|
||||
response.end("Read error");
|
||||
} else {
|
||||
response.destroy();
|
||||
}
|
||||
});
|
||||
stream.pipe(response);
|
||||
}
|
||||
});
|
||||
state.sendResponse(status,{"Content-Type": type},content);
|
||||
});
|
||||
} else {
|
||||
state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||
responseHeaders = {
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /login-basic -- force a Basic Authentication challenge
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/login-basic$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
if(!state.authenticatedUsername) {
|
||||
// Challenge if there's no username
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /status
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/status$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var text = JSON.stringify({
|
||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /:title
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/([^\/]+)$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title);
|
||||
@@ -33,8 +29,8 @@ exports.handler = function(request,response,state) {
|
||||
}
|
||||
var text = state.wiki.renderTiddler(renderType,renderTemplate,{parseAsInline: true, variables: {currentTiddler: title}});
|
||||
|
||||
var headers = {"Content-Type": renderType};
|
||||
state.sendResponse(200,headers,text,"utf8");
|
||||
// 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");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
|
||||
@@ -8,14 +8,10 @@ GET /recipes/default/tiddlers/:title
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
tiddler = state.wiki.getTiddler(title),
|
||||
|
||||
@@ -10,14 +10,10 @@ GET /recipes/default/tiddlers.json?filter=<filter>
|
||||
|
||||
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
||||
|
||||
exports.methods = ["GET"];
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
||||
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||
|
||||
@@ -8,14 +8,10 @@ PUT /recipes/default/tiddlers/:title
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
exports.methods = ["PUT"];
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.info = {
|
||||
priority: 100
|
||||
};
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
fields = $tw.utils.parseJSONSafe(state.data);
|
||||
|
||||
@@ -42,8 +42,6 @@ function Server(options) {
|
||||
}
|
||||
// Setup the default required plugins
|
||||
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
|
||||
@@ -76,11 +74,6 @@ function Server(options) {
|
||||
// console.log("Loading server route " + title);
|
||||
self.addRoute(routeDefinition);
|
||||
});
|
||||
this.routes.sort((a, b) => {
|
||||
const priorityA = a.info?.priority ?? 100,
|
||||
priorityB = b.info?.priority ?? 100;
|
||||
return priorityB - priorityA;
|
||||
});
|
||||
// Initialise the http vs https
|
||||
this.listenOptions = null;
|
||||
this.protocol = "http";
|
||||
@@ -224,7 +217,7 @@ Server.prototype.findMatchingRoute = function(request,state) {
|
||||
} else {
|
||||
match = potentialRoute.path.exec(pathname);
|
||||
}
|
||||
if(match && (potentialRoute.methods?.includes(request.method) || potentialRoute.method === request.method)) {
|
||||
if(match && request.method === potentialRoute.method) {
|
||||
state.params = [];
|
||||
for(var p=1; p<match.length; p++) {
|
||||
state.params.push(match[p]);
|
||||
@@ -263,13 +256,6 @@ 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";
|
||||
@@ -294,12 +280,6 @@ 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
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*\
|
||||
title: $:/core-modules/modules/utils/base64.js
|
||||
type: application/javascript
|
||||
module-type: utils-node
|
||||
|
||||
Base64 UTF-8 utlity functions.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const{ TextEncoder, TextDecoder } = require("node:util");
|
||||
|
||||
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
|
||||
|
||||
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
|
||||
|
||||
function base64ToBytes(base64) {
|
||||
const binString = exports.atob(base64);
|
||||
return Uint8Array.from(binString, m => m.codePointAt(0));
|
||||
};
|
||||
|
||||
function bytesToBase64(bytes) {
|
||||
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
|
||||
return exports.btoa(binString);
|
||||
};
|
||||
|
||||
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
|
||||
|
||||
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));
|
||||
@@ -1,95 +0,0 @@
|
||||
/*\
|
||||
title: $:/core-server/modules/utils/escapecss.js
|
||||
type: application/javascript
|
||||
module-type: utils-node
|
||||
|
||||
Provides CSS.escape() functionality.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
exports.escapeCSS = (function() {
|
||||
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||
|
||||
/* eslint-disable */
|
||||
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
||||
return function(value) {
|
||||
if (arguments.length == 0) {
|
||||
throw new TypeError('`CSS.escape` requires an argument.');
|
||||
}
|
||||
var string = String(value);
|
||||
var length = string.length;
|
||||
var index = -1;
|
||||
var codeUnit;
|
||||
var result = '';
|
||||
var firstCodeUnit = string.charCodeAt(0);
|
||||
while (++index < length) {
|
||||
codeUnit = string.charCodeAt(index);
|
||||
// Note: 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,4 +5,3 @@ 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,7 +6,6 @@ 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
|
||||
@@ -148,7 +147,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
||||
Settings/AutoSave/Enabled/Description: Save changes automatically
|
||||
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||
Settings/CamelCase/Hint: Requires reload to take effect
|
||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||
Settings/Caption: Settings
|
||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
title: $:/language/Draft/
|
||||
|
||||
Attribution: Draft of '<<draft-title>>' by {{$:/status/UserName}}
|
||||
Title: Draft of '<<draft-title>>'
|
||||
@@ -1,6 +1,5 @@
|
||||
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,11 +9,6 @@ Advanced/ShadowInfo/NotShadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text
|
||||
Advanced/ShadowInfo/Shadow/Hint: The tiddler <$link to=<<infoTiddler>>><$text text=<<infoTiddler>>/></$link> is a shadow tiddler
|
||||
Advanced/ShadowInfo/Shadow/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
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/background-actions.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class BackgroundActionDispatcher {
|
||||
constructor(filterTracker, wiki) {
|
||||
this.filterTracker = filterTracker;
|
||||
this.wiki = wiki;
|
||||
this.nextTrackedFilterId = 1;
|
||||
this.trackedFilters = new Map(); // Use Map for better key management
|
||||
|
||||
this.filterTracker.track({
|
||||
filterString: "[all[tiddlers+shadows]tag[$:/tags/BackgroundAction]!is[draft]]",
|
||||
fnEnter: title => this.trackFilter(title),
|
||||
fnLeave: (title, enterValue) => this.untrackFilter(enterValue),
|
||||
fnChange: (title, enterValue) => {
|
||||
this.untrackFilter(enterValue);
|
||||
return this.trackFilter(title);
|
||||
},
|
||||
fnProcess: changes => this.process(changes)
|
||||
});
|
||||
}
|
||||
|
||||
trackFilter(title) {
|
||||
const tiddler = this.wiki.getTiddler(title);
|
||||
const id = this.nextTrackedFilterId++;
|
||||
const tracker = new BackgroundActionTracker({
|
||||
wiki: this.wiki,
|
||||
title,
|
||||
trackFilter: tiddler.fields["track-filter"],
|
||||
actions: tiddler.fields.text
|
||||
});
|
||||
this.trackedFilters.set(id, tracker);
|
||||
return id;
|
||||
}
|
||||
|
||||
untrackFilter(enterValue) {
|
||||
const tracker = this.trackedFilters.get(enterValue);
|
||||
if(tracker) {
|
||||
tracker.destroy();
|
||||
}
|
||||
this.trackedFilters.delete(enterValue);
|
||||
}
|
||||
|
||||
process(changes) {
|
||||
for(const tracker of this.trackedFilters.values()) {
|
||||
tracker.process(changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BackgroundActionTracker {
|
||||
constructor({wiki, title, trackFilter, actions}) {
|
||||
this.wiki = wiki;
|
||||
this.title = title;
|
||||
this.trackFilter = trackFilter;
|
||||
this.actions = actions;
|
||||
this.filterTracker = new $tw.FilterTracker(this.wiki);
|
||||
this.hasChanged = false;
|
||||
this.trackerID = this.filterTracker.track({
|
||||
filterString: this.trackFilter,
|
||||
fnEnter: () => { this.hasChanged = true; },
|
||||
fnLeave: () => { this.hasChanged = true; },
|
||||
fnProcess: changes => {
|
||||
if(this.hasChanged) {
|
||||
this.hasChanged = false;
|
||||
console.log("Processing background action", this.title);
|
||||
const tiddler = this.wiki.getTiddler(this.title);
|
||||
let doActions = true;
|
||||
if(tiddler && tiddler.fields.platforms) {
|
||||
doActions = false;
|
||||
const platforms = $tw.utils.parseStringArray(tiddler.fields.platforms);
|
||||
if(($tw.browser && platforms.includes("browser")) || ($tw.node && platforms.includes("node"))) {
|
||||
doActions = true;
|
||||
}
|
||||
}
|
||||
if(doActions) {
|
||||
this.wiki.invokeActionString(
|
||||
this.actions,
|
||||
null,
|
||||
{
|
||||
currentTiddler: this.title
|
||||
},{
|
||||
parentWidget: $tw.rootWidget
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(changes) {
|
||||
this.filterTracker.handleChangeEvent(changes);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.filterTracker.untrack(this.trackerID);
|
||||
}
|
||||
}
|
||||
|
||||
exports.BackgroundActionDispatcher = BackgroundActionDispatcher;
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/config.js
|
||||
type: application/javascript
|
||||
module-type: config
|
||||
|
||||
Core configuration constants
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/deserializers.js
|
||||
type: application/javascript
|
||||
module-type: tiddlerdeserializer
|
||||
|
||||
Functions to deserialise tiddlers from a block of text
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -34,6 +37,12 @@ exports["application/json"] = function(text,fields) {
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Parse an HTML file into tiddlers. There are three possibilities:
|
||||
# A TiddlyWiki classic HTML file containing `text/x-tiddlywiki` tiddlers
|
||||
# A TiddlyWiki5 HTML file containing `text/vnd.tiddlywiki` tiddlers
|
||||
# An ordinary HTML file
|
||||
*/
|
||||
exports["text/html"] = function(text,fields) {
|
||||
var results = [];
|
||||
// Check if we've got an old-style store area
|
||||
@@ -51,11 +60,11 @@ exports["text/html"] = function(text,fields) {
|
||||
results.push.apply(results,deserializeNewStoreArea(text,newStoreAreaMarkerRegExp.lastIndex,newStoreAreaMatch[1],fields));
|
||||
newStoreAreaMatch = newStoreAreaMarkerRegExp.exec(text);
|
||||
}
|
||||
|
||||
// Return if we had either an old-style or a new-style store area
|
||||
if(storeAreaMatch || haveHadNewStoreArea) {
|
||||
return results;
|
||||
}
|
||||
|
||||
// Otherwise, check whether we've got an encrypted file
|
||||
var encryptedStoreArea = $tw.utils.extractEncryptedStoreArea(text);
|
||||
if(encryptedStoreArea) {
|
||||
// If so, attempt to decrypt it using the current password
|
||||
@@ -115,18 +124,30 @@ function deserializeStoreArea(text,storeAreaEnd,isTiddlyWiki5,fields) {
|
||||
return results;
|
||||
}
|
||||
|
||||
var deserializeTiddlerDiv = function(text) {
|
||||
/*
|
||||
Utility function to parse an old-style tiddler DIV in a *.tid file. It looks like this:
|
||||
|
||||
<div title="Title" creator="JoeBloggs" modifier="JoeBloggs" created="201102111106" modified="201102111310" tags="myTag [[my long tag]]">
|
||||
<pre>The text of the tiddler (without the expected HTML encoding).
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
Note that the field attributes are HTML encoded, but that the body of the <PRE> tag is not encoded.
|
||||
|
||||
When these tiddler DIVs are encountered within a TiddlyWiki HTML file then the body is encoded in the usual way.
|
||||
*/
|
||||
var deserializeTiddlerDiv = function(text /* [,fields] */) {
|
||||
// Slot together the default results
|
||||
var result = {};
|
||||
if(arguments.length > 1) {
|
||||
for(var f=1; f<arguments.length; f++) {
|
||||
var fields = arguments[f];
|
||||
for(var t in fields) {
|
||||
result[t] = fields[t];
|
||||
result[t] = fields[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the DIV body
|
||||
var startRegExp = /^\s*<div\s+([^>]*)>(\s*<pre>)?/gi,
|
||||
endRegExp,
|
||||
match = startRegExp.exec(text);
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/engines/framed.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Text editor engine based on a simple input or textarea within an iframe. This is done so that the selection is preserved even when clicking away from the textarea
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -31,7 +34,7 @@ function FramedEngine(options) {
|
||||
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||
this.iframeDoc.open();
|
||||
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
|
||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
||||
this.iframeDoc.close();
|
||||
// Style the iframe
|
||||
this.iframeNode.className = this.dummyTextArea.className;
|
||||
@@ -53,7 +56,7 @@ function FramedEngine(options) {
|
||||
} else {
|
||||
this.domNode.value = this.value;
|
||||
}
|
||||
|
||||
// Set the attributes
|
||||
if(this.widget.editType && this.widget.editTag !== "textarea") {
|
||||
this.domNode.setAttribute("type",this.widget.editType);
|
||||
}
|
||||
@@ -75,7 +78,7 @@ function FramedEngine(options) {
|
||||
if(this.widget.isDisabled === "yes") {
|
||||
this.domNode.setAttribute("disabled",true);
|
||||
}
|
||||
|
||||
// Copy the styles from the dummy textarea
|
||||
this.copyStyles();
|
||||
// Add event listeners
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
@@ -96,10 +99,13 @@ function FramedEngine(options) {
|
||||
{name: "click",handlerObject: this.widget,handlerMethod: "handleClickEvent"}
|
||||
]);
|
||||
}
|
||||
|
||||
// Insert the element into the DOM
|
||||
this.iframeDoc.body.appendChild(this.domNode);
|
||||
}
|
||||
|
||||
/*
|
||||
Copy styles from the dummy text area to the textarea in the iframe
|
||||
*/
|
||||
FramedEngine.prototype.copyStyles = function() {
|
||||
// Copy all styles
|
||||
$tw.utils.copyStyles(this.dummyTextArea,this.domNode);
|
||||
@@ -121,11 +127,14 @@ FramedEngine.prototype.setText = function(text,type) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode) {
|
||||
this.updateDomNodeText(text);
|
||||
}
|
||||
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
@@ -134,15 +143,21 @@ FramedEngine.prototype.updateDomNodeText = function(text) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get the text of the engine
|
||||
*/
|
||||
FramedEngine.prototype.getText = function() {
|
||||
return this.domNode.value;
|
||||
};
|
||||
|
||||
/*
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
FramedEngine.prototype.fixHeight = function() {
|
||||
// Make sure styles are updated
|
||||
this.copyStyles();
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
|
||||
// Adjust height
|
||||
if(this.widget.editTag === "textarea") {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
@@ -157,6 +172,9 @@ FramedEngine.prototype.fixHeight = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Focus the engine node
|
||||
*/
|
||||
FramedEngine.prototype.focus = function() {
|
||||
if(this.domNode.focus) {
|
||||
this.domNode.focus();
|
||||
@@ -166,12 +184,18 @@ FramedEngine.prototype.focus = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a focus event
|
||||
*/
|
||||
FramedEngine.prototype.handleFocusEvent = function(event) {
|
||||
if(this.widget.editCancelPopups) {
|
||||
$tw.popup.cancel(0);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a keydown event
|
||||
*/
|
||||
FramedEngine.prototype.handleKeydownEvent = function(event) {
|
||||
if ($tw.keyboardManager.handleKeydownEvent(event, {onlyPriority: true})) {
|
||||
return true;
|
||||
@@ -180,11 +204,17 @@ FramedEngine.prototype.handleKeydownEvent = function(event) {
|
||||
return this.widget.handleKeydownEvent(event);
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a click
|
||||
*/
|
||||
FramedEngine.prototype.handleClickEvent = function(event) {
|
||||
this.fixHeight();
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "input" event which occurs when the text has changed
|
||||
*/
|
||||
FramedEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
@@ -194,6 +224,9 @@ FramedEngine.prototype.handleInputEvent = function(event) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Create a blank structure representing a text operation
|
||||
*/
|
||||
FramedEngine.prototype.createTextOperation = function() {
|
||||
var operation = {
|
||||
text: this.domNode.value,
|
||||
@@ -209,6 +242,9 @@ FramedEngine.prototype.createTextOperation = function() {
|
||||
return operation;
|
||||
};
|
||||
|
||||
/*
|
||||
Execute a text operation
|
||||
*/
|
||||
FramedEngine.prototype.executeTextOperation = function(operation) {
|
||||
// Perform the required changes to the text area and the underlying tiddler
|
||||
var newText = operation.text;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/engines/simple.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Text editor engine based on a simple input or textarea tag
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -27,7 +30,7 @@ function SimpleEngine(options) {
|
||||
} else {
|
||||
this.domNode.value = this.value;
|
||||
}
|
||||
|
||||
// Set the attributes
|
||||
if(this.widget.editType && this.widget.editTag !== "textarea") {
|
||||
this.domNode.setAttribute("type",this.widget.editType);
|
||||
}
|
||||
@@ -52,7 +55,7 @@ function SimpleEngine(options) {
|
||||
if(this.widget.isDisabled === "yes") {
|
||||
this.domNode.setAttribute("disabled",true);
|
||||
}
|
||||
|
||||
// Add an input event handler
|
||||
$tw.utils.addEventListeners(this.domNode,[
|
||||
{name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"},
|
||||
{name: "input", handlerObject: this, handlerMethod: "handleInputEvent"}
|
||||
@@ -62,16 +65,22 @@ function SimpleEngine(options) {
|
||||
this.widget.domNodes.push(this.domNode);
|
||||
}
|
||||
|
||||
/*
|
||||
Set the text of the engine if it doesn't currently have focus
|
||||
*/
|
||||
SimpleEngine.prototype.setText = function(text,type) {
|
||||
if(!this.domNode.isTiddlyWikiFakeDom) {
|
||||
if(this.domNode.ownerDocument.activeElement !== this.domNode || text === "") {
|
||||
this.updateDomNodeText(text);
|
||||
}
|
||||
|
||||
// Fix the height if needed
|
||||
this.fixHeight();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the DomNode with the new text
|
||||
*/
|
||||
SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
try {
|
||||
this.domNode.value = text;
|
||||
@@ -80,13 +89,18 @@ SimpleEngine.prototype.updateDomNodeText = function(text) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get the text of the engine
|
||||
*/
|
||||
SimpleEngine.prototype.getText = function() {
|
||||
return this.domNode.value;
|
||||
};
|
||||
|
||||
/*
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
SimpleEngine.prototype.fixHeight = function() {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
|
||||
if(this.widget.editTag === "textarea") {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
@@ -99,6 +113,9 @@ SimpleEngine.prototype.fixHeight = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Focus the engine node
|
||||
*/
|
||||
SimpleEngine.prototype.focus = function() {
|
||||
if(this.domNode.focus) {
|
||||
this.domNode.focus();
|
||||
@@ -108,6 +125,9 @@ SimpleEngine.prototype.focus = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "input" event which occurs when the text has changed
|
||||
*/
|
||||
SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
this.widget.saveChanges(this.getText());
|
||||
this.fixHeight();
|
||||
@@ -117,6 +137,9 @@ SimpleEngine.prototype.handleInputEvent = function(event) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "focus" event
|
||||
*/
|
||||
SimpleEngine.prototype.handleFocusEvent = function(event) {
|
||||
if(this.widget.editCancelPopups) {
|
||||
$tw.popup.cancel(0);
|
||||
@@ -132,10 +155,16 @@ SimpleEngine.prototype.handleFocusEvent = function(event) {
|
||||
return true;
|
||||
};
|
||||
|
||||
/*
|
||||
Create a blank structure representing a text operation
|
||||
*/
|
||||
SimpleEngine.prototype.createTextOperation = function() {
|
||||
return null;
|
||||
};
|
||||
|
||||
/*
|
||||
Execute a text operation
|
||||
*/
|
||||
SimpleEngine.prototype.executeTextOperation = function(operation) {
|
||||
};
|
||||
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
title: $:/core/modules/editor/factory.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Factory for constructing text editor widgets with specified engines for the toolbar and non-toolbar cases
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var DEFAULT_MIN_TEXT_AREA_HEIGHT = "100px"; // Minimum height of textareas in pixels
|
||||
|
||||
// Configuration tiddlers
|
||||
var HEIGHT_MODE_TITLE = "$:/config/TextEditor/EditorHeight/Mode";
|
||||
var ENABLE_TOOLBAR_TITLE = "$:/config/TextEditor/EnableToolbar";
|
||||
|
||||
@@ -44,8 +48,8 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.toolbarNode = this.document.createElement("div");
|
||||
this.toolbarNode.className = "tc-editor-toolbar";
|
||||
parent.insertBefore(this.toolbarNode,nextSibling);
|
||||
this.domNodes.push(this.toolbarNode);
|
||||
this.renderChildren(this.toolbarNode,null);
|
||||
this.domNodes.push(this.toolbarNode);
|
||||
}
|
||||
// Create our element
|
||||
var editInfo = this.getEditInfo(),
|
||||
@@ -64,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
// Fix height
|
||||
this.engine.fixHeight();
|
||||
// Focus if required
|
||||
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
|
||||
if(this.editFocus === "true" || this.editFocus === "yes") {
|
||||
this.engine.focus();
|
||||
}
|
||||
// Add widget message listeners
|
||||
@@ -137,6 +141,9 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
return {value: value || "", type: type, update: update};
|
||||
};
|
||||
|
||||
/*
|
||||
Handle an edit text operation message from the toolbar
|
||||
*/
|
||||
EditTextWidget.prototype.handleEditTextOperationMessage = function(event) {
|
||||
// Prepare information about the operation
|
||||
var operation = this.engine.createTextOperation();
|
||||
@@ -145,13 +152,16 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
if(handler) {
|
||||
handler.call(this,event,operation);
|
||||
}
|
||||
|
||||
// Execute the operation via the engine
|
||||
var newText = this.engine.executeTextOperation(operation);
|
||||
// Fix the tiddler height and save changes
|
||||
this.engine.fixHeight();
|
||||
this.saveChanges(newText);
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
EditTextWidget.prototype.execute = function() {
|
||||
// Get our parameters
|
||||
this.editTitle = this.getAttribute("tiddler",this.getVariable("currentTiddler"));
|
||||
@@ -191,7 +201,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
type = type || "text";
|
||||
}
|
||||
|
||||
// Get the rest of our parameters
|
||||
this.editTag = this.getAttribute("tag",tag) || "input";
|
||||
this.editType = this.getAttribute("type",type);
|
||||
// Make the child widgets
|
||||
@@ -201,6 +211,9 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
this.editShowToolbar = (this.editShowToolbar === "yes") && !!(this.children && this.children.length > 0) && (!this.document.isTiddlyWikiFakeDom);
|
||||
};
|
||||
|
||||
/*
|
||||
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
||||
*/
|
||||
EditTextWidget.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
// Completely rerender if any of our attributes have changed
|
||||
@@ -221,14 +234,24 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Update the editor with new text. This method is separate from updateEditorDomNode()
|
||||
so that subclasses can override updateEditor() and still use updateEditorDomNode()
|
||||
*/
|
||||
EditTextWidget.prototype.updateEditor = function(text,type) {
|
||||
this.updateEditorDomNode(text,type);
|
||||
};
|
||||
|
||||
/*
|
||||
Update the editor dom node with new text
|
||||
*/
|
||||
EditTextWidget.prototype.updateEditorDomNode = function(text,type) {
|
||||
this.engine.setText(text,type);
|
||||
};
|
||||
|
||||
/*
|
||||
Save changes back to the tiddler store
|
||||
*/
|
||||
EditTextWidget.prototype.saveChanges = function(text) {
|
||||
var editInfo = this.getEditInfo();
|
||||
if(text !== editInfo.value) {
|
||||
@@ -236,6 +259,9 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Handle a dom "keydown" event, which we'll bubble up to our container for the keyboard widgets benefit
|
||||
*/
|
||||
EditTextWidget.prototype.handleKeydownEvent = function(event) {
|
||||
// Check for a keyboard shortcut
|
||||
if(this.toolbarNode) {
|
||||
@@ -256,17 +282,20 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Propogate the event to the container
|
||||
if(this.propogateKeydownEvent(event)) {
|
||||
// Ignore the keydown if it was already handled
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, process the keydown normally
|
||||
return false;
|
||||
};
|
||||
|
||||
/*
|
||||
Propogate keydown events to our container for the keyboard widgets benefit
|
||||
*/
|
||||
EditTextWidget.prototype.propogateKeydownEvent = function(event) {
|
||||
var newEvent = this.cloneEvent(event,["keyCode","code","which","key","metaKey","ctrlKey","altKey","shiftKey"]);
|
||||
return !this.parentDomNode.dispatchEvent(newEvent);
|
||||
@@ -289,12 +318,16 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
return dispatchNode.dispatchEvent(newEvent);
|
||||
};
|
||||
|
||||
/*
|
||||
Propogate drag and drop events with File data to our container for the dropzone widgets benefit.
|
||||
If there are no Files, let the browser handle it.
|
||||
*/
|
||||
EditTextWidget.prototype.handleDropEvent = function(event) {
|
||||
if($tw.utils.dragEventContainsFiles(event)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.dispatchDOMEvent(this.cloneEvent(event,["dataTransfer"]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EditTextWidget.prototype.handlePasteEvent = function(event) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/bitmap/clear.js
|
||||
type: application/javascript
|
||||
module-type: bitmapeditoroperation
|
||||
|
||||
Bitmap editor operation to clear the image
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/bitmap/resize.js
|
||||
type: application/javascript
|
||||
module-type: bitmapeditoroperation
|
||||
|
||||
Bitmap editor operation to resize the image
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -14,7 +17,7 @@ exports["resize"] = function(event) {
|
||||
if(newWidth > 0 && newHeight > 0 && !(newWidth === this.currCanvas.width && newHeight === this.currCanvas.height)) {
|
||||
this.changeCanvasSize(newWidth,newHeight);
|
||||
}
|
||||
|
||||
// Update the input controls
|
||||
this.refreshToolbar();
|
||||
// Save the image into the tiddler
|
||||
this.saveChanges();
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/bitmap/rotate-left.js
|
||||
type: application/javascript
|
||||
module-type: bitmapeditoroperation
|
||||
|
||||
Bitmap editor operation to rotate the image left by 90 degrees
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/excise.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to excise the selection to a new tiddler
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/insert-text.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation insert text at the caret position. If there is a selection it is replaced.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/make-link.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to make a link
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/prefix-lines.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to add a prefix to the selected lines
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -23,16 +26,16 @@ exports["prefix-lines"] = function(event,operation) {
|
||||
line = line.substring(event.paramObject.character.length);
|
||||
count++;
|
||||
}
|
||||
|
||||
// Remove any whitespace
|
||||
while(line.charAt(0) === " ") {
|
||||
line = line.substring(1);
|
||||
}
|
||||
|
||||
// We're done if we removed the exact required prefix, otherwise add it
|
||||
if(count !== targetCount) {
|
||||
// Apply the prefix
|
||||
line = prefix + " " + line;
|
||||
}
|
||||
|
||||
// Save the modified line
|
||||
lines[index] = line;
|
||||
});
|
||||
// Stitch the replacement text together and set the selection
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/replace-all.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to replace the entire text
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/replace-selection.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to replace the selection
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/save-selection.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to save the current selection in a specified tiddler
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/wrap-lines.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to wrap the selected lines with a prefix and suffix
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -12,14 +15,14 @@ exports["wrap-lines"] = function(event,operation) {
|
||||
if($tw.utils.endsWith(operation.text.substring(0,operation.selStart), prefix + "\n") &&
|
||||
$tw.utils.startsWith(operation.text.substring(operation.selEnd), "\n" + suffix)) {
|
||||
// Selected text is already surrounded by prefix and suffix: Remove them
|
||||
|
||||
// Cut selected text plus prefix and suffix
|
||||
operation.cutStart = operation.selStart - (prefix.length + 1);
|
||||
operation.cutEnd = operation.selEnd + suffix.length + 1;
|
||||
// Also cut the following newline (if there is any)
|
||||
if (operation.text[operation.cutEnd] === "\n") {
|
||||
operation.cutEnd++;
|
||||
}
|
||||
|
||||
// Replace with selection
|
||||
operation.replacement = operation.text.substring(operation.selStart,operation.selEnd);
|
||||
// Select text that was in between prefix and suffix
|
||||
operation.newSelStart = operation.cutStart;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/editor/operations/text/wrap-selection.js
|
||||
type: application/javascript
|
||||
module-type: texteditoroperation
|
||||
|
||||
Text editor operation to wrap the selection with the specified prefix and suffix
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -14,11 +17,11 @@ exports["wrap-selection"] = function(event,operation) {
|
||||
selLength = o.selEnd - o.selStart;
|
||||
|
||||
// This function detects, if trailing spaces are part of the selection __and__ if the user wants to handle them
|
||||
|
||||
// Returns "yes", "start", "end", "no" (default)
|
||||
// yes .. there are trailing spaces at both ends
|
||||
|
||||
// start .. there are trailing spaces at the start
|
||||
// end .. there are trailing spaces at the end
|
||||
|
||||
// no .. no trailing spaces are taken into account
|
||||
var trailingSpaceAt = function(sel) {
|
||||
var _start,
|
||||
_end,
|
||||
@@ -61,6 +64,7 @@ exports["wrap-selection"] = function(event,operation) {
|
||||
}
|
||||
}
|
||||
|
||||
// options: lenPrefix, lenSuffix
|
||||
function removePrefixSuffix(options) {
|
||||
options = options || {};
|
||||
var _lenPrefix = options.lenPrefix || 0;
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/filter-tracker.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
class FilterTracker {
|
||||
constructor(wiki) {
|
||||
this.wiki = wiki;
|
||||
this.trackers = new Map();
|
||||
this.nextTrackerId = 1;
|
||||
}
|
||||
|
||||
handleChangeEvent(changes) {
|
||||
this.processTrackers();
|
||||
this.processChanges(changes);
|
||||
}
|
||||
|
||||
track(options = {}) {
|
||||
const {
|
||||
filterString,
|
||||
fnEnter,
|
||||
fnLeave,
|
||||
fnChange,
|
||||
fnProcess
|
||||
} = options;
|
||||
const id = this.nextTrackerId++;
|
||||
const tracker = {
|
||||
id,
|
||||
filterString,
|
||||
fnEnter,
|
||||
fnLeave,
|
||||
fnChange,
|
||||
fnProcess,
|
||||
previousResults: [],
|
||||
resultValues: {}
|
||||
};
|
||||
this.trackers.set(id, tracker);
|
||||
// Process the tracker
|
||||
this.processTracker(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
untrack(id) {
|
||||
this.trackers.delete(id);
|
||||
}
|
||||
|
||||
processTrackers() {
|
||||
for(const id of this.trackers.keys()) {
|
||||
this.processTracker(id);
|
||||
}
|
||||
}
|
||||
|
||||
processTracker(id) {
|
||||
const tracker = this.trackers.get(id);
|
||||
if(!tracker) return;
|
||||
const results = [];
|
||||
// Evaluate the filter and remove duplicate results
|
||||
$tw.utils.each(this.wiki.filterTiddlers(tracker.filterString), title => {
|
||||
$tw.utils.pushTop(results, title);
|
||||
});
|
||||
// Process the newly entered results
|
||||
results.forEach(title => {
|
||||
if(!tracker.previousResults.includes(title) && !tracker.resultValues[title] && tracker.fnEnter) {
|
||||
tracker.resultValues[title] = tracker.fnEnter(title) || true;
|
||||
}
|
||||
});
|
||||
// Process the results that have just left
|
||||
tracker.previousResults.forEach(title => {
|
||||
if(!results.includes(title) && tracker.resultValues[title] && tracker.fnLeave) {
|
||||
tracker.fnLeave(title, tracker.resultValues[title]);
|
||||
delete tracker.resultValues[title];
|
||||
}
|
||||
});
|
||||
// Update the previous results
|
||||
tracker.previousResults = results;
|
||||
}
|
||||
|
||||
processChanges(changes) {
|
||||
for(const tracker of this.trackers.values()) {
|
||||
Object.keys(changes).forEach(title => {
|
||||
if(title && tracker.previousResults.includes(title) && tracker.fnChange) {
|
||||
tracker.resultValues[title] = tracker.fnChange(title, tracker.resultValues[title]) || tracker.resultValues[title];
|
||||
}
|
||||
});
|
||||
if(tracker.fnProcess) {
|
||||
tracker.fnProcess(changes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.FilterTracker = FilterTracker;
|
||||
@@ -2,10 +2,17 @@
|
||||
title: $:/core/modules/filterrunprefixes/all.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Union of sets without de-duplication.
|
||||
Equivalent to = filter run prefix.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.all = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.push.apply(results, operationSubFunction(source,widget));
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
title: $:/core/modules/filterrunprefixes/and.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Intersection of sets.
|
||||
Equivalent to + filter run prefix.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.and = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
// This replaces all the elements of the array, but keeps the actual array so that references to it are preserved
|
||||
|
||||
@@ -6,6 +6,9 @@ module-type: filterrunprefix
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.cascade = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
@@ -21,7 +24,7 @@ exports.cascade = function(operationSubFunction,options) {
|
||||
}
|
||||
var output = filterFnList[index](options.wiki.makeTiddlerIterator([title]),widget.makeFakeWidgetWithVariables({
|
||||
"currentTiddler": "" + title,
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",{defaultValue:""})
|
||||
"..currentTiddler": widget.getVariable("currentTiddler","")
|
||||
}));
|
||||
if(output.length !== 0) {
|
||||
result = output[0];
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filterrunprefixes/else.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Equivalent to ~ filter run prefix.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.else = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length === 0) {
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
title: $:/core/modules/filterrunprefixes/except.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Difference of sets.
|
||||
Equivalent to - filter run prefix.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.except = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.remove(operationSubFunction(source,widget));
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
title: $:/core/modules/filterrunprefixes/filter.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.filter = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
@@ -14,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",{defaultValue:""}),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
title: $:/core/modules/filterrunprefixes/intersection.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.intersection = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/filterrunprefixes/let.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var variables = {};
|
||||
variables[name] = resultList;
|
||||
// Return the variables
|
||||
return {
|
||||
variables: variables
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -6,6 +6,9 @@ module-type: filterrunprefix
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.map = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
@@ -17,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",{defaultValue:""}),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler",""),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (inputTitles.length - 1 - index),
|
||||
"length": "" + inputTitles.length
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filterrunprefixes/or.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Equivalent to a filter run with no prefix.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.or = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
results.pushTop(operationSubFunction(source,widget));
|
||||
|
||||
@@ -6,6 +6,9 @@ module-type: filterrunprefix
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.reduce = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
@@ -14,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",{defaultValue:""}),
|
||||
"..currentTiddler": widget.getVariable("currentTiddler"),
|
||||
"index": "" + index,
|
||||
"revIndex": "" + (results.length - 1 - index),
|
||||
"length": "" + results.length,
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
title: $:/core/modules/filterrunprefixes/sort.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.sort = function(operationSubFunction,options) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length > 0) {
|
||||
@@ -20,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",{defaultValue:""})
|
||||
"..currentTiddler": widget.getVariable("currentTiddler")
|
||||
}));
|
||||
sortKeys.push(key[0] || "");
|
||||
});
|
||||
@@ -29,7 +33,7 @@ exports.sort = function(operationSubFunction,options) {
|
||||
for(var t=0; t<inputTitles.length; t++) {
|
||||
indexes[t] = t;
|
||||
}
|
||||
|
||||
// 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]);
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filterrunprefixes/then.js
|
||||
type: application/javascript
|
||||
module-type: filterrunprefix
|
||||
|
||||
Replace results of previous runs unless empty
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter prefix function
|
||||
*/
|
||||
exports.then = function(operationSubFunction) {
|
||||
return function(results,source,widget) {
|
||||
if(results.length !== 0) {
|
||||
|
||||
@@ -2,29 +2,40 @@
|
||||
title: $:/core/modules/filters.js
|
||||
type: application/javascript
|
||||
module-type: wikimethod
|
||||
|
||||
Adds tiddler filtering methods to the $tw.Wiki object.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var widgetClass = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
/* Maximum permitted filter recursion depth */
|
||||
var MAX_FILTER_DEPTH = 300;
|
||||
|
||||
/*
|
||||
Parses an operation (i.e. a run) within a filter string
|
||||
operators: Array of array of operator nodes into which results should be inserted
|
||||
filterString: filter string
|
||||
p: start position within the string
|
||||
Returns the new start position, after the parsed operation
|
||||
*/
|
||||
function parseFilterOperation(operators,filterString,p) {
|
||||
var nextBracketPos, operator;
|
||||
// Skip the starting square bracket
|
||||
if(filterString.charAt(p++) !== "[") {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
|
||||
// Process each operator in turn
|
||||
do {
|
||||
operator = {};
|
||||
// Check for an operator prefix
|
||||
if(filterString.charAt(p) === "!") {
|
||||
operator.prefix = filterString.charAt(p++);
|
||||
}
|
||||
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
|
||||
// Get the operator name
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
@@ -44,12 +55,12 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operator.suffixes[operator.suffixes.length - 1].push(entry);
|
||||
operator.suffixes[operator.suffixes.length - 1].push(entry);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Empty operator means: title
|
||||
else if(operator.operator === "") {
|
||||
operator.operator = "title";
|
||||
}
|
||||
@@ -68,10 +79,6 @@ 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));
|
||||
@@ -105,7 +112,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));
|
||||
@@ -114,31 +121,27 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
}
|
||||
}
|
||||
|
||||
// Push this operator
|
||||
operators.push(operator);
|
||||
} while(filterString.charAt(p) !== "]");
|
||||
// Skip the ending square bracket
|
||||
if(filterString.charAt(p++) !== "]") {
|
||||
throw "Missing ] in filter expression";
|
||||
}
|
||||
|
||||
// Return the parsing position
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse a filter string
|
||||
*/
|
||||
exports.parseFilter = function(filterString) {
|
||||
filterString = filterString || "";
|
||||
var results = [], // Array of arrays of operator nodes {operator:,operand:}
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
// Groups:
|
||||
// 1 - entire filter run prefix
|
||||
|
||||
// 3 - filter run prefix suffixes
|
||||
|
||||
// 5 - double quoted string following filter run prefix
|
||||
|
||||
// 7 - anything except for whitespace and square brackets
|
||||
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -146,48 +149,41 @@ exports.parseFilter = function(filterString) {
|
||||
if(match && match.index === p) {
|
||||
p = p + match[0].length;
|
||||
}
|
||||
|
||||
// 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: []
|
||||
};
|
||||
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];
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(match[4]) {
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
} else {
|
||||
// No filter run prefix
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
}
|
||||
|
||||
if(match[4]) { // Opening square bracket
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
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]}]}
|
||||
@@ -220,6 +216,11 @@ exports.filterTiddlers = function(filterString,widget,source) {
|
||||
return fn.call(this,source,widget);
|
||||
};
|
||||
|
||||
/*
|
||||
Compile a filter into a function with the signature fn(source,widget) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
*/
|
||||
exports.compileFilter = function(filterString) {
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
@@ -237,7 +238,7 @@ exports.compileFilter = function(filterString) {
|
||||
return [$tw.language.getString("Error/Filter") + ": " + e];
|
||||
};
|
||||
}
|
||||
|
||||
// Get the hashmap of filter operator functions
|
||||
var filterOperators = this.getFilterOperators();
|
||||
// Assemble array of functions, one for each operation
|
||||
var operationFunctions = [];
|
||||
@@ -250,8 +251,6 @@ 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
|
||||
@@ -267,29 +266,13 @@ 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
|
||||
@@ -297,8 +280,6 @@ exports.compileFilter = function(filterString) {
|
||||
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,
|
||||
@@ -338,9 +319,7 @@ 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:
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
@@ -366,13 +345,7 @@ exports.compileFilter = function(filterString) {
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
} else {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
@@ -382,7 +355,7 @@ exports.compileFilter = function(filterString) {
|
||||
});
|
||||
if(this.filterCacheCount >= 2000) {
|
||||
// To prevent memory leak, we maintain an upper limit for cache size.
|
||||
|
||||
// Reset if exceeded. This should give us 95% of the benefit
|
||||
// that no cache limit would give us.
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
title: $:/core/modules/filters/addprefix.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for adding a prefix to each title in the list. This is
|
||||
especially useful in contexts where only a filter expression is allowed
|
||||
and macro substitution isn't available.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.addprefix = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
title: $:/core/modules/filters/addsuffix.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for adding a suffix to each title in the list. This is
|
||||
especially useful in contexts where only a filter expression is allowed
|
||||
and macro substitution isn't available.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.addsuffix = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/after.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the tiddler from the current list that is after the tiddler named in the operand.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.after = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
title: $:/core/modules/filters/all.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for selecting tiddlers
|
||||
|
||||
[all[shadows+tiddlers]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
@@ -16,6 +21,9 @@ function getAllFilterOperators() {
|
||||
return allFilterOperators;
|
||||
}
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.all = function(source,operator,options) {
|
||||
// Check for common optimisations
|
||||
var subops = operator.operand.split("+");
|
||||
@@ -30,7 +38,7 @@ exports.all = function(source,operator,options) {
|
||||
} else if(subops.length === 2 && subops[0] === "shadows" && subops[1] === "tiddlers") {
|
||||
return options.wiki.eachShadowPlusTiddlers;
|
||||
}
|
||||
|
||||
// Do it the hard way
|
||||
// Get our suboperators
|
||||
var allFilterOperators = getAllFilterOperators();
|
||||
// Cycle through the suboperators accumulating their results
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/current.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[current]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.current = function(source,prefix,options) {
|
||||
var currTiddlerTitle = options.widget && options.widget.getVariable("currentTiddler");
|
||||
if(currTiddlerTitle) {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/missing.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[missing]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.missing = function(source,prefix,options) {
|
||||
return options.wiki.getMissingTitles();
|
||||
};
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/orphans.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[orphans]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.orphans = function(source,prefix,options) {
|
||||
return options.wiki.getOrphanTitles();
|
||||
};
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/shadows.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[shadows]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.shadows = function(source,prefix,options) {
|
||||
return options.wiki.allShadowTitles();
|
||||
};
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/tags.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[tags]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tags = function(source,prefix,options) {
|
||||
return Object.keys(options.wiki.getTagMap());
|
||||
};
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/all/tiddlers.js
|
||||
type: application/javascript
|
||||
module-type: allfilteroperator
|
||||
|
||||
Filter function for [all[tiddlers]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.tiddlers = function(source,prefix,options) {
|
||||
return options.wiki.allTitles();
|
||||
};
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/backlinks.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning all the backlinks from a tiddler
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backlinks = function(source,operator,options) {
|
||||
var results = new $tw.utils.LinkedList();
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
title: $:/core/modules/filters/backtranscludes.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning all the backtranscludes from a tiddler
|
||||
|
||||
\*/
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.backtranscludes = function(source,operator,options) {
|
||||
var results = new $tw.utils.LinkedList();
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/before.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the tiddler from the current list that is before the tiddler named in the operand.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.before = function(source,operator,options) {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/commands.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the names of the commands available in this wiki
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.commands = function(source,operator,options) {
|
||||
var results = [];
|
||||
$tw.utils.each($tw.commands,function(commandInfo,name) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/filters/compare.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
General purpose comparison operator
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/contains.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for finding values in array fields
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.contains = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldname = operator.suffix || "list";
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/count.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator returning the number of entries in the current list.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.count = function(source,operator,options) {
|
||||
var count = 0;
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
title: $:/core/modules/filters/crypto.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operators for cryptography, using the Stanford JavaScript library
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/days.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator that selects tiddlers with a specified date field within a specified date interval.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.days = function(source,operator,options) {
|
||||
var results = [],
|
||||
fieldName = operator.suffix || "modified",
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/deserializers.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the names of the deserializers in this wiki
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.deserializers = function(source,operator,options) {
|
||||
var results = [];
|
||||
$tw.utils.each($tw.Wiki.tiddlerDeserializerModules,function(deserializer,type) {
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/duplicateslugs.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter function for [duplicateslugs[]]
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.duplicateslugs = function(source,operator,options) {
|
||||
var slugs = Object.create(null), // Hashmap by slug of title, replaced with "true" if the duplicate title has already been output
|
||||
results = [];
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
title: $:/core/modules/filters/each.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator that selects one tiddler for each unique value of the specified field.
|
||||
With suffix "list", selects all tiddlers that are values in a specified list field.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.each = function(source,operator,options) {
|
||||
var results =[] ,
|
||||
value,values = {},
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/eachday.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator that selects one tiddler for each unique day covered by the specified date field
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.eachday = function(source,operator,options) {
|
||||
var results = [],
|
||||
values = [],
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
title: $:/core/modules/filters/editiondescription.js
|
||||
type: application/javascript
|
||||
module-type: filteroperator
|
||||
|
||||
Filter operator for returning the descriptions of the specified edition names
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Export our filter function
|
||||
*/
|
||||
exports.editiondescription = function(source,operator,options) {
|
||||
var results = [];
|
||||
if($tw.node) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user