mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-25 20:33:41 +00:00
Compare commits
230 Commits
new-releas
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cde9c931c8 | ||
|
|
d07fe25cdb | ||
|
|
a40ce29451 | ||
|
|
75647eb623 | ||
|
|
eb3a80968e | ||
|
|
62ae4b24bc | ||
|
|
ded76aa84f | ||
|
|
e42ed6808e | ||
|
|
844564180f | ||
|
|
a670de0e95 | ||
|
|
faee49ee01 | ||
|
|
dd20be49f0 | ||
|
|
a27f74bbdc | ||
|
|
ae4e99951a | ||
|
|
be84dee26b | ||
|
|
00e17874f0 | ||
|
|
9041f099a3 | ||
|
|
3ba31be2a8 | ||
|
|
99d8afd515 | ||
|
|
2ab5f26644 | ||
|
|
419fe68ee2 | ||
|
|
0e765bdbdb | ||
|
|
855d8a9638 | ||
|
|
afcf108d29 | ||
|
|
8f9acc0ca2 | ||
|
|
5e4b8fbb3c | ||
|
|
8e301178a4 | ||
|
|
a72d3a09bf | ||
|
|
56634ffe29 | ||
|
|
24c317e1ab | ||
|
|
07329c6849 | ||
|
|
47ab3476f6 | ||
|
|
f0e64660f2 | ||
|
|
9663e65f4b | ||
|
|
7cb422242a | ||
|
|
f075f24e6b | ||
|
|
5fa1098c03 | ||
|
|
92dc927c7b | ||
|
|
98a61f01bb | ||
|
|
f3fa69e229 | ||
|
|
e2fb22ade0 | ||
|
|
7fb8560908 | ||
|
|
ff7814360e | ||
|
|
2d9303c6ff | ||
|
|
6aee5eb0c7 | ||
|
|
6eb881bffe | ||
|
|
2a5ce95d99 | ||
|
|
bd4fdd8f2e | ||
|
|
09379abd5d | ||
|
|
c6906120d8 | ||
|
|
c4c60933f4 | ||
|
|
a3979cda9c | ||
|
|
3c8ee86e23 | ||
|
|
921c0174fb | ||
|
|
4196d96adc | ||
|
|
743e99d12d | ||
|
|
6beeb23d10 | ||
|
|
838fad916d | ||
|
|
935e89bd93 | ||
|
|
1b8a2caa23 | ||
|
|
ecba671bcf | ||
|
|
fc1e53a777 | ||
|
|
2b6bdcbf97 | ||
|
|
119706a918 | ||
|
|
86d15585b6 | ||
|
|
4b824795c8 | ||
|
|
cd173a959d | ||
|
|
86d61e09bd | ||
|
|
7c197f6ecc | ||
|
|
8f8b46dab7 | ||
|
|
7b013af240 | ||
|
|
05f3e6d5a0 | ||
|
|
48eeb4603a | ||
|
|
fc74219c0b | ||
|
|
86c4770a28 | ||
|
|
ffde2da16c | ||
|
|
da41a55f29 | ||
|
|
846ac9a0dd | ||
|
|
65edda224b | ||
|
|
41dac42f3b | ||
|
|
87d9754a4e | ||
|
|
5cd3084298 | ||
|
|
4c27c09b4d | ||
|
|
4bb0bc5527 | ||
|
|
6cb333b65b | ||
|
|
3378497816 | ||
|
|
033d5cf225 | ||
|
|
52d73eb1a8 | ||
|
|
5d1c1eaf87 | ||
|
|
ed4a186c9c | ||
|
|
f16c0d769b | ||
|
|
298508c104 | ||
|
|
f1e1532949 | ||
|
|
3e1078eff1 | ||
|
|
cc348fee96 | ||
|
|
24d45fd318 | ||
|
|
9fd345ec06 | ||
|
|
30e9b4f3b7 | ||
|
|
c6556d5207 | ||
|
|
a8da7e0207 | ||
|
|
d5762b1fbb | ||
|
|
2b0739f06e | ||
|
|
d81204c6ab | ||
|
|
e339f112a4 | ||
|
|
e001c21bf5 | ||
|
|
7a9235e9d1 | ||
|
|
bbbc8c2c03 | ||
|
|
538482e9a9 | ||
|
|
df7973fc3e | ||
|
|
ae79736e82 | ||
|
|
102c236267 | ||
|
|
06a2923adf | ||
|
|
244251ed44 | ||
|
|
9164f305e0 | ||
|
|
64f86c2187 | ||
|
|
54e5ef7489 | ||
|
|
2d2ba61949 | ||
|
|
0bbe170cf0 | ||
|
|
6f306d1ed6 | ||
|
|
845f988ab0 | ||
|
|
234667cc31 | ||
|
|
f1ce35036e | ||
|
|
5dfdbc8ea0 | ||
|
|
3cf71365a5 | ||
|
|
799618d9f5 | ||
|
|
4d4d9d9995 | ||
|
|
19177964c8 | ||
|
|
c8e41bfade | ||
|
|
fb4d417629 | ||
|
|
20d6be1e23 | ||
|
|
7898cb8446 | ||
|
|
9a5f4cc0ef | ||
|
|
cda8d7ca8c | ||
|
|
f38e9f0822 | ||
|
|
5848d66e96 | ||
|
|
485051951e | ||
|
|
135e685811 | ||
|
|
99682c5731 | ||
|
|
d58eec47c0 | ||
|
|
059978ec63 | ||
|
|
b5e20a58a6 | ||
|
|
e8fe6b98bc | ||
|
|
317104774c | ||
|
|
deed8631d8 | ||
|
|
d733b77e2f | ||
|
|
46c26a64b9 | ||
|
|
ec81d6663b | ||
|
|
23f0a9bf79 | ||
|
|
bad87c405e | ||
|
|
6f23a078b7 | ||
|
|
c3706b8a79 | ||
|
|
7ca8fb29af | ||
|
|
d39bb5274e | ||
|
|
81b69783c4 | ||
|
|
40cc62f727 | ||
|
|
b349adde16 | ||
|
|
d63a1896b3 | ||
|
|
b65fa11643 | ||
|
|
4043499633 | ||
|
|
6a39a4e13b | ||
|
|
b5153c0066 | ||
|
|
b061f90f87 | ||
|
|
8be83cf01b | ||
|
|
5b5147dade | ||
|
|
ad6ac480f9 | ||
|
|
8168512e95 | ||
|
|
276fdc8634 | ||
|
|
0b38ced43a | ||
|
|
d7e48207b9 | ||
|
|
2c8fafee48 | ||
|
|
a6383aaaea | ||
|
|
61619c07c8 | ||
|
|
09a42a54c0 | ||
|
|
f4f31c37fc | ||
|
|
61e638c972 | ||
|
|
6bdd51d72a | ||
|
|
ed3405672a | ||
|
|
e3af967cbb | ||
|
|
6b0d3fab5d | ||
|
|
13f1689e7e | ||
|
|
4c09a88272 | ||
|
|
fbf110e209 | ||
|
|
3c1d658fad | ||
|
|
5d738673ac | ||
|
|
91871d2ced | ||
|
|
5143da9cce | ||
|
|
186d1b014a | ||
|
|
58e41ee0ad | ||
|
|
97824cc3a3 | ||
|
|
6e493755be | ||
|
|
64fce62075 | ||
|
|
5a4ff56477 | ||
|
|
3889a2a0d0 | ||
|
|
34737f4e28 | ||
|
|
94673a1028 | ||
|
|
b462aaa9a3 | ||
|
|
4552c117fc | ||
|
|
dc7f2a57bb | ||
|
|
7e91bac6b8 | ||
|
|
15ba415a45 | ||
|
|
2405e65308 | ||
|
|
865f36a6f5 | ||
|
|
a36356a07d | ||
|
|
ee23097816 | ||
|
|
e753851d49 | ||
|
|
cae3d0fa2c | ||
|
|
7c020d0eb6 | ||
|
|
afe2ac45d9 | ||
|
|
6791f0f130 | ||
|
|
a2e5c2cca2 | ||
|
|
87ba87bdd2 | ||
|
|
619bdfcab5 | ||
|
|
5ff4e02a61 | ||
|
|
f8170cd50a | ||
|
|
5389dc0fa7 | ||
|
|
2cc7c96eec | ||
|
|
8cd3d4e22c | ||
|
|
37e09d1c25 | ||
|
|
7a080092d0 | ||
|
|
810ac42810 | ||
|
|
88d3f69a3b | ||
|
|
e956bb32e9 | ||
|
|
dd91ac0b82 | ||
|
|
af63a3b920 | ||
|
|
e4fb47ee76 | ||
|
|
7944f42467 | ||
|
|
578c09e0ce | ||
|
|
ffb0a2fde2 | ||
|
|
c5a80a1984 | ||
|
|
c22046a2c2 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
boot/** -linguist-generated
|
||||||
|
**/tiddlywiki.files linguist-language=JSON
|
||||||
|
**/tiddlywiki.info linguist-language=JSON
|
||||||
|
**/plugin.info linguist-language=JSON
|
||||||
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve TiddlyWiki 5
|
||||||
|
title: "[Report] "
|
||||||
|
type: report
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Remove elements, that you do not need -->
|
||||||
|
<!-- Add screenshots where needed -->
|
||||||
|
|
||||||
|
**Problem Description**
|
||||||
|
<!-- Describe your problem: A clear and concise description of what your problem is -->
|
||||||
|
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
|
||||||
|
1. At https://tiddlywiki.com
|
||||||
|
2. Click on ...
|
||||||
|
3. Scroll down to ...
|
||||||
|
4. See ...
|
||||||
|
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
|
||||||
|
As a user,
|
||||||
|
<!-- As a developer, -->
|
||||||
|
I would expect ...
|
||||||
|
|
||||||
|
|
||||||
|
**TiddlyWiki Configuration**
|
||||||
|
<!-- Please complete the following information -->
|
||||||
|
|
||||||
|
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
|
||||||
|
|
||||||
|
<!-- Your report comes here -->
|
||||||
|
<!-- or -->
|
||||||
|
<!-- Add it manually -->
|
||||||
|
|
||||||
|
- Version: <!-- e.g. v5.3.8 -->
|
||||||
|
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
|
||||||
|
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
|
||||||
|
|
||||||
|
|
||||||
|
**Desktop**
|
||||||
|
<!-- Please complete the following information -->
|
||||||
|
|
||||||
|
- OS: <!-- e.g. iOS -->
|
||||||
|
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
|
||||||
|
|
||||||
|
**Smartphone**
|
||||||
|
<!-- Please complete the following information -->
|
||||||
|
|
||||||
|
- Device: <!-- e.g. iPhone6 -->
|
||||||
|
- OS: <!-- e.g. iOS8.1 -->
|
||||||
|
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
|
||||||
|
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context about the problem here. -->
|
||||||
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,67 +0,0 @@
|
|||||||
name: Bug report
|
|
||||||
description: Create a report to help us improve TiddlyWiki 5
|
|
||||||
title: "[BUG] "
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
id: Describe
|
|
||||||
attributes:
|
|
||||||
label: Describe the bug
|
|
||||||
description: A clear and concise description of what the bug is.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: Expected
|
|
||||||
attributes:
|
|
||||||
label: Expected behavior
|
|
||||||
description: A clear and concise description of what you expected to happen.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: Reproduce
|
|
||||||
attributes:
|
|
||||||
label: To Reproduce
|
|
||||||
description: "Steps to reproduce the behavior:"
|
|
||||||
placeholder: |
|
|
||||||
1. Go to '...'
|
|
||||||
2. Click on '....'
|
|
||||||
3. Scroll down to '....'
|
|
||||||
4. See error
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: Screenshots
|
|
||||||
attributes:
|
|
||||||
label: Screenshots
|
|
||||||
description: If applicable, add screenshots to help explain your problem.
|
|
||||||
placeholder: Drag image here to upload screenshot!
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
id: Configuration
|
|
||||||
attributes:
|
|
||||||
label: TiddlyWiki Configuration
|
|
||||||
description: please complete the following information
|
|
||||||
placeholder: |
|
|
||||||
- Version [e.g. v5.1.24]
|
|
||||||
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
|
|
||||||
- Plugins installed [e.g. Freelinks, TiddlyMap]
|
|
||||||
|
|
||||||
### Desktop (please complete the following information):
|
|
||||||
|
|
||||||
- OS: [e.g. iOS]
|
|
||||||
- Browser [e.g. chrome, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
|
|
||||||
### Smartphone (please complete the following information):
|
|
||||||
|
|
||||||
- Device: [e.g. iPhone6]
|
|
||||||
- OS: [e.g. iOS8.1]
|
|
||||||
- Browser [e.g. stock browser, safari]
|
|
||||||
- Version [e.g. 22]
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: Context
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add any other context about the problem here.
|
|
||||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -4,17 +4,23 @@ about: Suggest an idea for TiddlyWiki 5
|
|||||||
title: "[IDEA]"
|
title: "[IDEA]"
|
||||||
labels: ''
|
labels: ''
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
type: idea
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your idea related to a problem? Please describe.**
|
||||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
||||||
|
A clear and concise description of what the problem is. Eg:
|
||||||
|
As a user, I would like [...]
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
|
|
||||||
A clear and concise description of what you want to happen.
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
**Describe alternatives you've considered**
|
||||||
|
|
||||||
A clear and concise description of any alternative solutions or features you've considered.
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
|
||||||
Add any other context or screenshots about the feature request here.
|
Add any other context or screenshots about the feature request here.
|
||||||
|
|||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
@@ -62,7 +62,7 @@ jobs:
|
|||||||
TW5_BUILD_OUTPUT: "./output"
|
TW5_BUILD_OUTPUT: "./output"
|
||||||
TW5_BUILD_ARCHIVE: "./output"
|
TW5_BUILD_ARCHIVE: "./output"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
|
|||||||
40
.github/workflows/eslint.yml
vendored
Normal file
40
.github/workflows/eslint.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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:
|
steps:
|
||||||
- name: build-size-check
|
- name: build-size-check
|
||||||
id: get_sizes
|
id: get_sizes
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ github.event.pull_request.number }}
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
repo: ${{ github.repository }}
|
repo: ${{ github.repository }}
|
||||||
|
|||||||
2
.github/workflows/pr-comment-build-size.yml
vendored
2
.github/workflows/pr-comment-build-size.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Build and check size
|
- name: Build and check size
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ inputs.pr_number }}
|
pr_number: ${{ inputs.pr_number }}
|
||||||
repo: ${{ github.repository }}
|
repo: ${{ github.repository }}
|
||||||
|
|||||||
18
.github/workflows/pr-path-validation.yml
vendored
18
.github/workflows/pr-path-validation.yml
vendored
@@ -1,18 +0,0 @@
|
|||||||
name: Validate PR Paths
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate-pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Validate PR
|
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
|
||||||
with:
|
|
||||||
pr_number: ${{ github.event.pull_request.number }}
|
|
||||||
repo: ${{ github.repository }}
|
|
||||||
base_ref: ${{ github.base_ref }}
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
37
.github/workflows/pr-validation.yml
vendored
Normal file
37
.github/workflows/pr-validation.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: PR Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
jobs:
|
||||||
|
validate-pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Step 1: Validate PR paths
|
||||||
|
- name: Validate PR Paths
|
||||||
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
|
with:
|
||||||
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
|
repo: ${{ github.repository }}
|
||||||
|
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
mode: rules
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Step 2: Validate change notes
|
||||||
|
- name: Validate Change Notes
|
||||||
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
|
with:
|
||||||
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
|
repo: ${{ github.repository }}
|
||||||
|
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
mode: changenotes
|
||||||
|
continue-on-error: false
|
||||||
|
|
||||||
@@ -73,10 +73,8 @@ 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/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/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/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/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)
|
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||||
|
|
||||||
@@ -301,26 +299,6 @@ node $TW5_BUILD_TIDDLYWIKI \
|
|||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||||
|| exit 1
|
|| 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/index.html Demo wiki with codemirror plugin
|
||||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
|
|||||||
151
boot/boot.js
151
boot/boot.js
@@ -8,6 +8,8 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
|
|||||||
|
|
||||||
\*/
|
\*/
|
||||||
|
|
||||||
|
/* eslint-disable @stylistic/indent */
|
||||||
|
|
||||||
var _boot = (function($tw) {
|
var _boot = (function($tw) {
|
||||||
|
|
||||||
/*jslint node: true, browser: true */
|
/*jslint node: true, browser: true */
|
||||||
@@ -44,12 +46,8 @@ $tw.utils.hop = function(object,property) {
|
|||||||
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
|
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/** @deprecated Use Array.isArray instead */
|
||||||
Determine if a value is an array
|
$tw.utils.isArray = value => Array.isArray(value);
|
||||||
*/
|
|
||||||
$tw.utils.isArray = function(value) {
|
|
||||||
return Object.prototype.toString.call(value) == "[object Array]";
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if an array is equal by value and by reference.
|
Check if an array is equal by value and by reference.
|
||||||
@@ -128,35 +126,22 @@ $tw.utils.pushTop = function(array,value) {
|
|||||||
return array;
|
return array;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/** @deprecated Use instanceof Date instead */
|
||||||
Determine if a value is a date
|
$tw.utils.isDate = value => value instanceof 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) {
|
$tw.utils.each = function(object,callback) {
|
||||||
var next,f,length;
|
|
||||||
if(object) {
|
if(object) {
|
||||||
if(Object.prototype.toString.call(object) == "[object Array]") {
|
if(Array.isArray(object)) {
|
||||||
for(f=0, length=object.length; f<length; f++) {
|
object.every((element,index,array) => {
|
||||||
next = callback(object[f],f,object);
|
const next = callback(element,index,array);
|
||||||
if(next === false) {
|
return next !== false;
|
||||||
break;
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
var keys = Object.keys(object);
|
Object.entries(object).every(entry => {
|
||||||
for(f=0, length=keys.length; f<length; f++) {
|
const next = callback(entry[1], entry[0], object);
|
||||||
var key = keys[f];
|
return next !== false;
|
||||||
next = callback(object[key],key,object);
|
});
|
||||||
if(next === false) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -331,32 +316,13 @@ $tw.utils.htmlDecode = function(s) {
|
|||||||
return s.toString().replace(/</mg,"<").replace(/ /mg,"\xA0").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&");
|
return s.toString().replace(/</mg,"<").replace(/ /mg,"\xA0").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&");
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/** @deprecated Use window.location.hash instead. */
|
||||||
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
|
$tw.utils.getLocationHash = () => window.location.hash;
|
||||||
*/
|
|
||||||
$tw.utils.getLocationHash = function() {
|
|
||||||
var href = window.location.href;
|
|
||||||
var idx = href.indexOf('#');
|
|
||||||
if(idx === -1) {
|
|
||||||
return "#";
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/** @deprecated Pad a string to a given length with "0"s. Length defaults to 2 */
|
||||||
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();
|
||||||
$tw.utils.pad = function(value,length) {
|
return s.padStart(length, "0");
|
||||||
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
|
// Convert a date into UTC YYYYMMDDHHMMSSmmm format
|
||||||
@@ -630,7 +596,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
|||||||
// Compile the code into a function
|
// Compile the code into a function
|
||||||
var fn;
|
var fn;
|
||||||
if($tw.browser) {
|
if($tw.browser) {
|
||||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
|
fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
|
||||||
} else {
|
} else {
|
||||||
if(sandbox){
|
if(sandbox){
|
||||||
fn = vm.runInContext(code,sandbox,filename)
|
fn = vm.runInContext(code,sandbox,filename)
|
||||||
@@ -641,7 +607,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
|||||||
// Call the function and return the exports
|
// Call the function and return the exports
|
||||||
return fn.apply(null,contextValues);
|
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
|
Run code in a sandbox with only the specified context variables in scope
|
||||||
*/
|
*/
|
||||||
@@ -799,12 +765,13 @@ the password, and to encrypt/decrypt a block of text
|
|||||||
$tw.utils.Crypto = function() {
|
$tw.utils.Crypto = function() {
|
||||||
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
||||||
currentPassword = null,
|
currentPassword = null,
|
||||||
callSjcl = function(method,inputText,password) {
|
callSjcl = function(method,inputText,password,options) {
|
||||||
|
options = options || {};
|
||||||
password = password || currentPassword;
|
password = password || currentPassword;
|
||||||
var outputText;
|
var outputText;
|
||||||
try {
|
try {
|
||||||
if(password) {
|
if(password) {
|
||||||
outputText = sjcl[method](password,inputText);
|
outputText = sjcl[method](password,inputText,options);
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
console.log("Crypto error:" + ex);
|
console.log("Crypto error:" + ex);
|
||||||
@@ -830,7 +797,8 @@ $tw.utils.Crypto = function() {
|
|||||||
return !!currentPassword;
|
return !!currentPassword;
|
||||||
}
|
}
|
||||||
this.encrypt = function(text,password) {
|
this.encrypt = function(text,password) {
|
||||||
return callSjcl("encrypt",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"});
|
||||||
};
|
};
|
||||||
this.decrypt = function(text,password) {
|
this.decrypt = function(text,password) {
|
||||||
return callSjcl("decrypt",text,password);
|
return callSjcl("decrypt",text,password);
|
||||||
@@ -1433,7 +1401,7 @@ $tw.Wiki = function(options) {
|
|||||||
checkTiddler = function(tiddler,title) {
|
checkTiddler = function(tiddler,title) {
|
||||||
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
||||||
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
||||||
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
||||||
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
||||||
pluginTiddlers.push(tiddler);
|
pluginTiddlers.push(tiddler);
|
||||||
registeredTitles.push(tiddler.fields.title);
|
registeredTitles.push(tiddler.fields.title);
|
||||||
@@ -1530,7 +1498,8 @@ Define all modules stored in ordinary tiddlers
|
|||||||
*/
|
*/
|
||||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||||
this.each(function(tiddler,title) {
|
this.each(function(tiddler,title) {
|
||||||
if(tiddler.hasField("module-type")) {
|
// Modules in draft tiddlers are disabled
|
||||||
|
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
|
||||||
switch(tiddler.fields.type) {
|
switch(tiddler.fields.type) {
|
||||||
case "application/javascript":
|
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
|
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||||
@@ -1557,6 +1526,11 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
|||||||
this.eachShadow(function(tiddler,title) {
|
this.eachShadow(function(tiddler,title) {
|
||||||
// Don't define the module if it is overidden by an ordinary tiddler
|
// Don't define the module if it is overidden by an ordinary tiddler
|
||||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
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
|
// Define the module
|
||||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||||
}
|
}
|
||||||
@@ -1905,7 +1879,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
|||||||
fileSize = fs.statSync(filepath).size,
|
fileSize = fs.statSync(filepath).size,
|
||||||
data;
|
data;
|
||||||
if(fileSize > $tw.config.maxEditFileSize) {
|
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);
|
console.log("Warning: " + data);
|
||||||
ext = ".txt";
|
ext = ".txt";
|
||||||
} else {
|
} else {
|
||||||
@@ -1976,22 +1950,41 @@ filepath: pathname of the directory containing the specification file
|
|||||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||||
var tiddlers = [];
|
var tiddlers = [];
|
||||||
// Read the specification
|
// Read the specification
|
||||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
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 {};
|
||||||
|
});
|
||||||
|
|
||||||
// Helper to process a file
|
// Helper to process a file
|
||||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||||
pathname = path.resolve(filepath,filename),
|
pathname = path.resolve(filepath,filename),
|
||||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
|
||||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||||
fileTiddlers;
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
if(isTiddlerFile) {
|
if(isTiddlerFile) {
|
||||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
|
||||||
} else {
|
} else {
|
||||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||||
}
|
}
|
||||||
var combinedFields = $tw.utils.extend({},fields,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(fileTiddlers,function(tiddler) {
|
||||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||||
@@ -2066,6 +2059,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
} else if(tidInfo.suffix) {
|
} else if(tidInfo.suffix) {
|
||||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||||
}
|
}
|
||||||
|
tidInfo.fields = tidInfo.fields || {};
|
||||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||||
});
|
});
|
||||||
// Process any listed directories
|
// Process any listed directories
|
||||||
@@ -2087,6 +2081,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
|||||||
var thisPath = path.relative(filepath, files[t]),
|
var thisPath = path.relative(filepath, files[t]),
|
||||||
filename = path.basename(thisPath);
|
filename = path.basename(thisPath);
|
||||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||||
|
dirSpec.fields = dirSpec.fields || {};
|
||||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2350,6 +2345,7 @@ $tw.loadTiddlersNode = function() {
|
|||||||
});
|
});
|
||||||
// Load the core tiddlers
|
// Load the core tiddlers
|
||||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
||||||
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
|
||||||
// Load any extra plugins
|
// Load any extra plugins
|
||||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||||
@@ -2423,6 +2419,7 @@ $tw.boot.initStartup = function(options) {
|
|||||||
// System paths and filenames
|
// System paths and filenames
|
||||||
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
||||||
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
||||||
|
$tw.boot.coreServerPath = path.resolve($tw.boot.bootPath,"../core-server");
|
||||||
// If there's no arguments then default to `--help`
|
// If there's no arguments then default to `--help`
|
||||||
if($tw.boot.argv.length === 0) {
|
if($tw.boot.argv.length === 0) {
|
||||||
$tw.boot.argv = ["--help"];
|
$tw.boot.argv = ["--help"];
|
||||||
@@ -2547,10 +2544,10 @@ $tw.boot.execStartup = function(options){
|
|||||||
if($tw.safeMode) {
|
if($tw.safeMode) {
|
||||||
$tw.wiki.processSafeMode();
|
$tw.wiki.processSafeMode();
|
||||||
}
|
}
|
||||||
// Register typed modules from the tiddlers we've just loaded
|
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
|
||||||
$tw.wiki.defineTiddlerModules();
|
// Tiddlers should appear last so that they may overwrite shadows during module registration
|
||||||
// And any modules within plugins
|
|
||||||
$tw.wiki.defineShadowModules();
|
$tw.wiki.defineShadowModules();
|
||||||
|
$tw.wiki.defineTiddlerModules();
|
||||||
// Make sure the crypto state tiddler is up to date
|
// Make sure the crypto state tiddler is up to date
|
||||||
if($tw.crypto) {
|
if($tw.crypto) {
|
||||||
$tw.crypto.updateCryptoStateTiddler();
|
$tw.crypto.updateCryptoStateTiddler();
|
||||||
@@ -2619,11 +2616,13 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
|||||||
$tw.boot.log(s.join(" "));
|
$tw.boot.log(s.join(" "));
|
||||||
// Execute task
|
// Execute task
|
||||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||||
task.startup();
|
const thenable = task.startup();
|
||||||
if(task.name) {
|
if(thenable && typeof thenable.then === "function"){
|
||||||
$tw.boot.executedStartupModules[task.name] = true;
|
thenable.then(asyncTaskCallback);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return asyncTaskCallback();
|
||||||
}
|
}
|
||||||
return $tw.boot.executeNextStartupTask(callback);
|
|
||||||
} else {
|
} else {
|
||||||
task.startup(asyncTaskCallback);
|
task.startup(asyncTaskCallback);
|
||||||
return true;
|
return true;
|
||||||
@@ -2768,6 +2767,8 @@ return $tw;
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* eslint-enable @stylistic/indent */
|
||||||
|
|
||||||
if(typeof(exports) !== "undefined") {
|
if(typeof(exports) !== "undefined") {
|
||||||
exports.TiddlyWiki = _boot;
|
exports.TiddlyWiki = _boot;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ See Boot.js for further details of the boot process.
|
|||||||
|
|
||||||
\*/
|
\*/
|
||||||
|
|
||||||
|
/* eslint-disable @stylistic/indent */
|
||||||
|
|
||||||
var _bootprefix = (function($tw) {
|
var _bootprefix = (function($tw) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -114,6 +116,8 @@ return $tw;
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* eslint-enable @stylistic/indent */
|
||||||
|
|
||||||
if(typeof(exports) === "undefined") {
|
if(typeof(exports) === "undefined") {
|
||||||
// Set up $tw global for the browser
|
// Set up $tw global for the browser
|
||||||
window.$tw = _bootprefix(window.$tw);
|
window.$tw = _bootprefix(window.$tw);
|
||||||
|
|||||||
14
community/people/ChristianByron.tid
Normal file
14
community/people/ChristianByron.tid
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
title: @Christian_Byron
|
||||||
|
tags: Community/Person
|
||||||
|
fullname: Christian Byron
|
||||||
|
talk.tiddlywiki.org: Christian_Byron
|
||||||
|
github: ceebeetree
|
||||||
|
linkedin: www.linkedin.com/in/christian-byron-b84a594/
|
||||||
|
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEBAAMBAAAAAAAAAAAAAAAHBgEDBQQBAAMBAAAAAAAAAAAAAAAAAAABAwX/2gAMAwEAAhADEAAAADv2xtJlY03sqePW3ARS1RSydIhcH//EACcQAAICAgIBAgYDAAAAAAAAAAECAwQFEQASMRMhBhBBk8HRIzJx/9oACAEBAAE/AMFQxs+NExqJLMCwYE+SOT4bF3qr+hAIpRsDQ6lWH0Yco4S/eVniRVQHXZzrZ5dwGQpQtNII2RfJVvHMRl5cbKxC94n/ALp+RxfiKpNcgMMUqPIwjcnWip/I5XtUowaL3Ujir/xt79Glb6/4OZ7MV5oEpUzuIa7MPB14A5jpoYLsEsydo1bbLre+CWEEEYab7Uf74ZYSSThpvtR/vmRmhnuzywp1jZtquta+VPM49qlcy24lf017At7g8uZnHrUsGK3Ez+m3UBvcnXy//8QAHhEAAgEFAAMAAAAAAAAAAAAAAQIDAAQRIkEyUaH/2gAIAQIBAT8AmiuVlZkLEeQOflJPcvMAF0z65V+h0YIW52rBDuxUrztf/8QAIxEBAAEDAwMFAAAAAAAAAAAAAgEAAxEEBSMSQcEiMVJxof/aAAgBAwEBPwC/Z1ZvNBOYz1Gc/lDUat3ySPRM/H2P3W4hcbIldpxnxW3BcjQk9oznzX//2Q==
|
||||||
|
|
||||||
|
Hello ~TiddlyWikiers - I have been a long time fan, recent contributor to the TW community.
|
||||||
|
Recently I have volunteered to run the [[TiddlyWiki Newsletter|https://tiddlywiki.substack.com/]] to spread the great news about TW.
|
||||||
|
|
||||||
|
I have been in the IT industry for about thirty years, mostly as a consultant and technical arcitect.
|
||||||
|
More recently I went back to study a masters in IT focussing on AI and data science.
|
||||||
|
Now my partner and I have started our own business ([[Sphere Innovations|https://sphere-innovations.com.au]]) - in consulting and building web applications for small to medium size businesses here in Australia.
|
||||||
@@ -6,6 +6,7 @@ talk.tiddlywiki.org: jeremyruston
|
|||||||
github: Jermolene
|
github: Jermolene
|
||||||
linkedin: www.linkedin.com/in/jermy
|
linkedin: www.linkedin.com/in/jermy
|
||||||
flickr: www.flickr.com/photos/jermy/
|
flickr: www.flickr.com/photos/jermy/
|
||||||
|
bluesky: https://bsky.app/profile/jermolene.bsky.social
|
||||||
homepage: jermolene.com
|
homepage: jermolene.com
|
||||||
email: jeremy@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=
|
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=
|
||||||
|
|||||||
19
community/people/LinOnetwo.tid
Normal file
19
community/people/LinOnetwo.tid
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
|
||||||
|
created: 20251110102157310
|
||||||
|
first-sighting: 2019-03-01
|
||||||
|
fullname: Lin Onetwo
|
||||||
|
github: linonetwo
|
||||||
|
homepage: https://wiki.onetwo.website/
|
||||||
|
modified: 20251111184556193
|
||||||
|
tags: Community/Person Community/Team/Contributors
|
||||||
|
talk.tiddlywiki.org: linonetwo
|
||||||
|
title: @linonetwo
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I don’t want to forget any of them. When I’m deeply focused on a task, it’s easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
|
||||||
|
|
||||||
|
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
|
||||||
|
|
||||||
|
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, I’ve enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
|
||||||
|
|
||||||
|
Most of my notes are open by default and shared publicly on my homepage as a digital garden.
|
||||||
25
community/people/PMario.tid
Normal file
25
community/people/PMario.tid
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
|
||||||
|
created: 20251110102157310
|
||||||
|
first-sighting: 2009-11-14
|
||||||
|
fullname: Mario Pietsch
|
||||||
|
github: pmario
|
||||||
|
homepage: https://wikilabs.github.io/
|
||||||
|
modified: 20251110124935183
|
||||||
|
tags: Community/Person Community/Team/Contributors
|
||||||
|
talk.tiddlywiki.org: pmario
|
||||||
|
title: @pmario
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
youtube: https://www.youtube.com/@pmario
|
||||||
|
|
||||||
|
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
|
||||||
|
|
||||||
|
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
|
||||||
|
|
||||||
|
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
|
||||||
|
|
||||||
|
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what that’s good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
|
||||||
|
|
||||||
|
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
|
||||||
|
|
||||||
|
Have fun!<br>
|
||||||
|
Mario
|
||||||
19
community/project/teams/Developer Experience Team.tid
Normal file
19
community/project/teams/Developer Experience Team.tid
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
title: Developer Experience Team
|
||||||
|
tags: Community/Team
|
||||||
|
modified: 20251109200632671
|
||||||
|
created: 20251109200632671
|
||||||
|
leader: @pmario
|
||||||
|
team: @saqimtiaz
|
||||||
|
|
||||||
|
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
|
||||||
|
|
||||||
|
Tools and resources managed by the Developer Experience Team include:
|
||||||
|
|
||||||
|
* Advising and assisting contributors, particularly new developers
|
||||||
|
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
|
||||||
|
** Development environment setup guides
|
||||||
|
** Code review processes and best practices
|
||||||
|
** Contribution guidelines and documentation
|
||||||
|
* Continuous integration and deployment scripts providing feedback on pull requests
|
||||||
|
* Devising and implementing labelling systems for issues and pull requests
|
||||||
|
* Automation scripts to simplify common development tasks
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
title: Infrastructure Team
|
|
||||||
tags: Community/Team
|
|
||||||
modified: 20250909171928024
|
|
||||||
created: 20250909171928024
|
created: 20250909171928024
|
||||||
|
modified: 20251110133437795
|
||||||
|
tags: Community/Team
|
||||||
team: @MotovunJack
|
team: @MotovunJack
|
||||||
|
title: Infrastructure Team
|
||||||
|
|
||||||
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
|
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
|
||||||
|
|
||||||
@@ -12,3 +12,4 @@ The infrastructure includes:
|
|||||||
* github.com/TiddlyWiki
|
* github.com/TiddlyWiki
|
||||||
* tiddlywiki.com DNS
|
* tiddlywiki.com DNS
|
||||||
* Netlify account for PR previews
|
* Netlify account for PR previews
|
||||||
|
* edit.tiddlywiki.com
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
title: Newsletter Team
|
|
||||||
tags: Community/Team
|
|
||||||
modified: 20250909171928024
|
|
||||||
created: 20250909171928024
|
|
||||||
|
|
||||||
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.
|
|
||||||
11
community/project/teams/Quality Assurance Team.tid
Normal file
11
community/project/teams/Quality Assurance Team.tid
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
title: Quality Assurance Team
|
||||||
|
created: 20251112125742296
|
||||||
|
modified: 20251112125742296
|
||||||
|
tags: Community/Team
|
||||||
|
team:
|
||||||
|
leader: @Leilei332
|
||||||
|
|
||||||
|
title: Quality Assurance Team
|
||||||
|
|
||||||
|
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.
|
||||||
|
|
||||||
15
community/project/teams/TiddlyWiki Newsletter Team.tid
Normal file
15
community/project/teams/TiddlyWiki Newsletter Team.tid
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
title: TiddlyWiki Newsletter Team
|
||||||
|
tags: Community/Team
|
||||||
|
modified: 20251219090709874
|
||||||
|
created: 20250909171928024
|
||||||
|
leader: @Christian_Byron
|
||||||
|
|
||||||
|
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
|
||||||
|
|
||||||
|
! Audience
|
||||||
|
|
||||||
|
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
|
||||||
|
|
||||||
|
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
|
||||||
|
|
||||||
|
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
title: Community/Team
|
title: Community/Team
|
||||||
modified: 20250909171928024
|
modified: 20250909171928024
|
||||||
created: 20250909171928024
|
created: 20250909171928024
|
||||||
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Infrastructure Team]] [[Succession Team]]
|
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
|
||||||
|
|
||||||
|
|||||||
@@ -99,16 +99,18 @@ Commander.prototype.executeNextCommand = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(command.info.synchronous) {
|
if(command.info.synchronous) {
|
||||||
// Synchronous command
|
// Synchronous command (await thenables)
|
||||||
c = new command.Command(params,this);
|
c = new command.Command(params,this);
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
} else {
|
} else {
|
||||||
this.executeNextCommand();
|
this.executeNextCommand();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Asynchronous command
|
// Asynchronous command (await thenables)
|
||||||
c = new command.Command(params,this,function(err) {
|
c = new command.Command(params,this,function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.callback(err);
|
self.callback(err);
|
||||||
@@ -117,7 +119,9 @@ Commander.prototype.executeNextCommand = function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { if(e) this.callback(e); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,6 +76,7 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
|
|||||||
"$:/boot/boot.js",
|
"$:/boot/boot.js",
|
||||||
"$:/boot/bootprefix.js",
|
"$:/boot/bootprefix.js",
|
||||||
"$:/core",
|
"$:/core",
|
||||||
|
"$:/core-server",
|
||||||
"$:/library/sjcl.js",
|
"$:/library/sjcl.js",
|
||||||
"$:/temp/info-plugin"
|
"$:/temp/info-plugin"
|
||||||
];
|
];
|
||||||
11
core-server/plugin.info
Normal file
11
core-server/plugin.info
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"title": "$:/core-server",
|
||||||
|
"name": "Core Server Components",
|
||||||
|
"description": "TiddlyWiki5 core server components",
|
||||||
|
"author": "JeremyRuston",
|
||||||
|
"core-version": ">=5.0.0",
|
||||||
|
"platform": "server",
|
||||||
|
"plugin-priority": "0",
|
||||||
|
"list": "readme",
|
||||||
|
"stability": "STABILITY_2_STABLE"
|
||||||
|
}
|
||||||
7
core-server/readme.tid
Normal file
7
core-server/readme.tid
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
title: $:/core-server/readme
|
||||||
|
|
||||||
|
This plugin contains TiddlyWiki's core components that are only needed on the server, comprising:
|
||||||
|
|
||||||
|
* Commands
|
||||||
|
* HTTP server code
|
||||||
|
* Utility functions for server
|
||||||
@@ -8,10 +8,14 @@ DELETE /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "DELETE";
|
exports.methods = ["DELETE"];
|
||||||
|
|
||||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||||
state.wiki.deleteTiddler(title);
|
state.wiki.deleteTiddler(title);
|
||||||
@@ -8,10 +8,14 @@ GET /favicon.ico
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/favicon.ico$/;
|
exports.path = /^\/favicon.ico$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||||
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||||
73
core-server/server/routes/get-file.js
Normal file
73
core-server/server/routes/get-file.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/server/routes/get-file.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: route
|
||||||
|
|
||||||
|
GET /files/:filepath
|
||||||
|
|
||||||
|
\*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
|
exports.path = /^\/files\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.handler = function(request,response,state) {
|
||||||
|
var path = require("path"),
|
||||||
|
fs = require("fs"),
|
||||||
|
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});
|
||||||
|
} else {
|
||||||
|
responseHeaders["Content-Length"] = stats.size;
|
||||||
|
response.writeHead(200, responseHeaders);
|
||||||
|
stream = fs.createReadStream(filename);
|
||||||
|
}
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -8,10 +8,14 @@ GET /
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/$/;
|
exports.path = /^\/$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||||
responseHeaders = {
|
responseHeaders = {
|
||||||
@@ -8,10 +8,14 @@ GET /login-basic -- force a Basic Authentication challenge
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/login-basic$/;
|
exports.path = /^\/login-basic$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
if(!state.authenticatedUsername) {
|
if(!state.authenticatedUsername) {
|
||||||
// Challenge if there's no username
|
// Challenge if there's no username
|
||||||
@@ -8,10 +8,14 @@ GET /status
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/status$/;
|
exports.path = /^\/status$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = JSON.stringify({
|
var text = JSON.stringify({
|
||||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||||
@@ -8,10 +8,14 @@ GET /:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/([^\/]+)$/;
|
exports.path = /^\/([^\/]+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title);
|
tiddler = state.wiki.getTiddler(title);
|
||||||
@@ -8,10 +8,14 @@ GET /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title),
|
tiddler = state.wiki.getTiddler(title),
|
||||||
@@ -10,10 +10,14 @@ GET /recipes/default/tiddlers.json?filter=<filter>
|
|||||||
|
|
||||||
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
||||||
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||||
@@ -8,10 +8,14 @@ PUT /recipes/default/tiddlers/:title
|
|||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "PUT";
|
exports.methods = ["PUT"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
fields = $tw.utils.parseJSONSafe(state.data);
|
fields = $tw.utils.parseJSONSafe(state.data);
|
||||||
@@ -42,6 +42,8 @@ function Server(options) {
|
|||||||
}
|
}
|
||||||
// Setup the default required plugins
|
// Setup the default required plugins
|
||||||
this.requiredPlugins = this.get("required-plugins").split(',');
|
this.requiredPlugins = this.get("required-plugins").split(',');
|
||||||
|
// Initialise CORS
|
||||||
|
this.corsEnable = this.get("cors-enable") === "yes";
|
||||||
// Initialise CSRF
|
// Initialise CSRF
|
||||||
this.csrfDisable = this.get("csrf-disable") === "yes";
|
this.csrfDisable = this.get("csrf-disable") === "yes";
|
||||||
// Initialize Gzip compression
|
// Initialize Gzip compression
|
||||||
@@ -74,6 +76,11 @@ function Server(options) {
|
|||||||
// console.log("Loading server route " + title);
|
// console.log("Loading server route " + title);
|
||||||
self.addRoute(routeDefinition);
|
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
|
// Initialise the http vs https
|
||||||
this.listenOptions = null;
|
this.listenOptions = null;
|
||||||
this.protocol = "http";
|
this.protocol = "http";
|
||||||
@@ -217,7 +224,7 @@ Server.prototype.findMatchingRoute = function(request,state) {
|
|||||||
} else {
|
} else {
|
||||||
match = potentialRoute.path.exec(pathname);
|
match = potentialRoute.path.exec(pathname);
|
||||||
}
|
}
|
||||||
if(match && request.method === potentialRoute.method) {
|
if(match && (potentialRoute.methods?.includes(request.method) || potentialRoute.method === request.method)) {
|
||||||
state.params = [];
|
state.params = [];
|
||||||
for(var p=1; p<match.length; p++) {
|
for(var p=1; p<match.length; p++) {
|
||||||
state.params.push(match[p]);
|
state.params.push(match[p]);
|
||||||
@@ -256,6 +263,13 @@ Server.prototype.requestHandler = function(request,response,options) {
|
|||||||
state.urlInfo = url.parse(request.url);
|
state.urlInfo = url.parse(request.url);
|
||||||
state.queryParameters = querystring.parse(state.urlInfo.query);
|
state.queryParameters = querystring.parse(state.urlInfo.query);
|
||||||
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
state.pathPrefix = options.pathPrefix || this.get("path-prefix") || "";
|
||||||
|
// Enable CORS
|
||||||
|
if(this.corsEnable) {
|
||||||
|
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
response.setHeader("Access-Control-Allow-Headers", "*");
|
||||||
|
response.setHeader("Access-Control-Allow-Methods", "*");
|
||||||
|
response.setHeader("Access-Control-Expose-Headers", "*");
|
||||||
|
}
|
||||||
state.sendResponse = sendResponse.bind(self,request,response);
|
state.sendResponse = sendResponse.bind(self,request,response);
|
||||||
// Get the principals authorized to access this resource
|
// Get the principals authorized to access this resource
|
||||||
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
state.authorizationType = options.authorizationType || this.methodMappings[request.method] || "readers";
|
||||||
@@ -280,6 +294,12 @@ Server.prototype.requestHandler = function(request,response,options) {
|
|||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Reply to OPTIONS
|
||||||
|
if(this.corsEnable && request.method === "OPTIONS") {
|
||||||
|
response.writeHead(204);
|
||||||
|
response.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Find the route that matches this path
|
// Find the route that matches this path
|
||||||
var route = self.findMatchingRoute(request,state);
|
var route = self.findMatchingRoute(request,state);
|
||||||
// Optionally output debug info
|
// Optionally output debug info
|
||||||
30
core-server/utils/base64.js
Normal file
30
core-server/utils/base64.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core-modules/modules/utils/base64.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: utils-node
|
||||||
|
|
||||||
|
Base64 UTF-8 utlity functions.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const{ TextEncoder, TextDecoder } = require("node:util");
|
||||||
|
|
||||||
|
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
|
||||||
|
|
||||||
|
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
|
||||||
|
|
||||||
|
function base64ToBytes(base64) {
|
||||||
|
const binString = exports.atob(base64);
|
||||||
|
return Uint8Array.from(binString, m => m.codePointAt(0));
|
||||||
|
};
|
||||||
|
|
||||||
|
function bytesToBase64(bytes) {
|
||||||
|
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
|
||||||
|
return exports.btoa(binString);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
|
||||||
|
|
||||||
|
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));
|
||||||
95
core-server/utils/escapecss.js
Normal file
95
core-server/utils/escapecss.js
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core-server/modules/utils/escapecss.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: utils-node
|
||||||
|
|
||||||
|
Provides CSS.escape() functionality.
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.escapeCSS = (function() {
|
||||||
|
// see also https://drafts.csswg.org/cssom/#serialize-an-identifier
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
/*! https://mths.be/cssescape v1.5.1 by @mathias | MIT license */
|
||||||
|
return function(value) {
|
||||||
|
if (arguments.length == 0) {
|
||||||
|
throw new TypeError('`CSS.escape` requires an argument.');
|
||||||
|
}
|
||||||
|
var string = String(value);
|
||||||
|
var length = string.length;
|
||||||
|
var index = -1;
|
||||||
|
var codeUnit;
|
||||||
|
var result = '';
|
||||||
|
var firstCodeUnit = string.charCodeAt(0);
|
||||||
|
while (++index < length) {
|
||||||
|
codeUnit = string.charCodeAt(index);
|
||||||
|
// Note: there’s no need to special-case astral symbols, surrogate
|
||||||
|
// pairs, or lone surrogates.
|
||||||
|
|
||||||
|
// If the character is NULL (U+0000), then the REPLACEMENT CHARACTER
|
||||||
|
// (U+FFFD).
|
||||||
|
if (codeUnit == 0x0000) {
|
||||||
|
result += '\uFFFD';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// If the character is in the range [\1-\1F] (U+0001 to U+001F) or is
|
||||||
|
// U+007F, […]
|
||||||
|
(codeUnit >= 0x0001 && codeUnit <= 0x001F) || codeUnit == 0x007F ||
|
||||||
|
// If the character is the first character and is in the range [0-9]
|
||||||
|
// (U+0030 to U+0039), […]
|
||||||
|
(index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) ||
|
||||||
|
// If the character is the second character and is in the range [0-9]
|
||||||
|
// (U+0030 to U+0039) and the first character is a `-` (U+002D), […]
|
||||||
|
(
|
||||||
|
index == 1 &&
|
||||||
|
codeUnit >= 0x0030 && codeUnit <= 0x0039 &&
|
||||||
|
firstCodeUnit == 0x002D
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
|
||||||
|
result += '\\' + codeUnit.toString(16) + ' ';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
// If the character is the first character and is a `-` (U+002D), and
|
||||||
|
// there is no second character, […]
|
||||||
|
index == 0 &&
|
||||||
|
length == 1 &&
|
||||||
|
codeUnit == 0x002D
|
||||||
|
) {
|
||||||
|
result += '\\' + string.charAt(index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the character is not handled by one of the above rules and is
|
||||||
|
// greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or
|
||||||
|
// is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to
|
||||||
|
// U+005A), or [a-z] (U+0061 to U+007A), […]
|
||||||
|
if (
|
||||||
|
codeUnit >= 0x0080 ||
|
||||||
|
codeUnit == 0x002D ||
|
||||||
|
codeUnit == 0x005F ||
|
||||||
|
codeUnit >= 0x0030 && codeUnit <= 0x0039 ||
|
||||||
|
codeUnit >= 0x0041 && codeUnit <= 0x005A ||
|
||||||
|
codeUnit >= 0x0061 && codeUnit <= 0x007A
|
||||||
|
) {
|
||||||
|
// the character itself
|
||||||
|
result += string.charAt(index);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the escaped character.
|
||||||
|
// https://drafts.csswg.org/cssom/#escape-a-character
|
||||||
|
result += '\\' + string.charAt(index);
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
/* eslint-enable */
|
||||||
|
})();
|
||||||
@@ -5,3 +5,4 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
|
|||||||
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
||||||
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
||||||
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
|
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
|
||||||
|
* [[diff-match-patch-es by antfu|https://github.com/antfu/diff-match-patch-es]]
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
|||||||
Settings/AutoSave/Enabled/Description: 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/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
Settings/CamelCase/Hint: Requires reload to take effect
|
||||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||||
Settings/Caption: Settings
|
Settings/Caption: Settings
|
||||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
title: $:/language/
|
title: $:/language/
|
||||||
|
|
||||||
|
Alerts: Alerts
|
||||||
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
|
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
|
||||||
BinaryWarning/Prompt: This tiddler contains binary data
|
BinaryWarning/Prompt: This tiddler contains binary data
|
||||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.
|
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ function FramedEngine(options) {
|
|||||||
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||||
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||||
this.iframeDoc.open();
|
this.iframeDoc.open();
|
||||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
|
||||||
this.iframeDoc.close();
|
this.iframeDoc.close();
|
||||||
// Style the iframe
|
// Style the iframe
|
||||||
this.iframeNode.className = this.dummyTextArea.className;
|
this.iframeNode.className = this.dummyTextArea.className;
|
||||||
@@ -156,8 +156,8 @@ Fix the height of textarea to fit content
|
|||||||
FramedEngine.prototype.fixHeight = function() {
|
FramedEngine.prototype.fixHeight = function() {
|
||||||
// Make sure styles are updated
|
// Make sure styles are updated
|
||||||
this.copyStyles();
|
this.copyStyles();
|
||||||
// Adjust height
|
// If .editRows is initialised, it takes precedence
|
||||||
if(this.widget.editTag === "textarea") {
|
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
|
||||||
if(this.widget.editAutoHeight) {
|
if(this.widget.editAutoHeight) {
|
||||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ SimpleEngine.prototype.getText = function() {
|
|||||||
Fix the height of textarea to fit content
|
Fix the height of textarea to fit content
|
||||||
*/
|
*/
|
||||||
SimpleEngine.prototype.fixHeight = function() {
|
SimpleEngine.prototype.fixHeight = function() {
|
||||||
if(this.widget.editTag === "textarea") {
|
// If .editRows is initialised, it takes precedence
|
||||||
|
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
|
||||||
if(this.widget.editAutoHeight) {
|
if(this.widget.editAutoHeight) {
|
||||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||||
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
|||||||
// Fix height
|
// Fix height
|
||||||
this.engine.fixHeight();
|
this.engine.fixHeight();
|
||||||
// Focus if required
|
// Focus if required
|
||||||
if(this.editFocus === "true" || this.editFocus === "yes") {
|
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
|
||||||
this.engine.focus();
|
this.engine.focus();
|
||||||
}
|
}
|
||||||
// Add widget message listeners
|
// Add widget message listeners
|
||||||
|
|||||||
41
core/modules/filterrunprefixes/let.js
Normal file
41
core/modules/filterrunprefixes/let.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/filterrunprefixes/let.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filterrunprefix
|
||||||
|
|
||||||
|
Assign a value to a variable
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter prefix function
|
||||||
|
*/
|
||||||
|
exports.let = function(operationSubFunction,options) {
|
||||||
|
// Return the filter run prefix function
|
||||||
|
return function(results,source,widget) {
|
||||||
|
// Save the result list
|
||||||
|
var resultList = results.toArray();
|
||||||
|
// Clear the results
|
||||||
|
results.clear();
|
||||||
|
// Evaluate the subfunction to get the variable name
|
||||||
|
var subFunctionResults = operationSubFunction(source,widget);
|
||||||
|
if(subFunctionResults.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var name = subFunctionResults[0];
|
||||||
|
if(typeof name !== "string" || name.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Assign the result of the subfunction to the variable
|
||||||
|
var variables = {};
|
||||||
|
variables[name] = resultList;
|
||||||
|
// Return the variables
|
||||||
|
return {
|
||||||
|
variables: variables
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -35,7 +35,7 @@ function parseFilterOperation(operators,filterString,p) {
|
|||||||
operator.prefix = filterString.charAt(p++);
|
operator.prefix = filterString.charAt(p++);
|
||||||
}
|
}
|
||||||
// Get the operator name
|
// Get the operator name
|
||||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
|
||||||
if(nextBracketPos === -1) {
|
if(nextBracketPos === -1) {
|
||||||
throw "Missing [ in filter expression";
|
throw "Missing [ in filter expression";
|
||||||
}
|
}
|
||||||
@@ -79,13 +79,17 @@ function parseFilterOperation(operators,filterString,p) {
|
|||||||
operand.variable = true;
|
operand.variable = true;
|
||||||
nextBracketPos = filterString.indexOf(">",p);
|
nextBracketPos = filterString.indexOf(">",p);
|
||||||
break;
|
break;
|
||||||
|
case "(": // Round brackets
|
||||||
|
operand.multiValuedVariable = true;
|
||||||
|
nextBracketPos = filterString.indexOf(")",p);
|
||||||
|
break;
|
||||||
case "/": // regexp brackets
|
case "/": // regexp brackets
|
||||||
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||||
rexMatch = rex.exec(filterString.substring(p));
|
rexMatch = rex.exec(filterString.substring(p));
|
||||||
if(rexMatch) {
|
if(rexMatch) {
|
||||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||||
// DEPRECATION WARNING
|
// DEPRECATION WARNING
|
||||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||||
nextBracketPos = p + rex.lastIndex - 1;
|
nextBracketPos = p + rex.lastIndex - 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -112,7 +116,7 @@ function parseFilterOperation(operators,filterString,p) {
|
|||||||
// Check for multiple operands
|
// Check for multiple operands
|
||||||
while(filterString.charAt(p) === ",") {
|
while(filterString.charAt(p) === ",") {
|
||||||
p++;
|
p++;
|
||||||
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
if(/^[\[\{<\/\(]/.test(filterString.substring(p))) {
|
||||||
nextBracketPos = p;
|
nextBracketPos = p;
|
||||||
p++;
|
p++;
|
||||||
parseOperand(filterString.charAt(nextBracketPos));
|
parseOperand(filterString.charAt(nextBracketPos));
|
||||||
@@ -141,7 +145,15 @@ exports.parseFilter = function(filterString) {
|
|||||||
p = 0, // Current position in the filter string
|
p = 0, // Current position in the filter string
|
||||||
match;
|
match;
|
||||||
var whitespaceRegExp = /(\s+)/mg,
|
var whitespaceRegExp = /(\s+)/mg,
|
||||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
// Groups:
|
||||||
|
// 1 - entire filter run prefix
|
||||||
|
// 2 - filter run prefix itself
|
||||||
|
// 3 - filter run prefix suffixes
|
||||||
|
// 4 - opening square bracket following filter run prefix
|
||||||
|
// 5 - double quoted string following filter run prefix
|
||||||
|
// 6 - single quoted string following filter run prefix
|
||||||
|
// 7 - anything except for whitespace and square brackets
|
||||||
|
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||||
while(p < filterString.length) {
|
while(p < filterString.length) {
|
||||||
// Skip any whitespace
|
// Skip any whitespace
|
||||||
whitespaceRegExp.lastIndex = p;
|
whitespaceRegExp.lastIndex = p;
|
||||||
@@ -152,38 +164,45 @@ exports.parseFilter = function(filterString) {
|
|||||||
// Match the start of the operation
|
// Match the start of the operation
|
||||||
if(p < filterString.length) {
|
if(p < filterString.length) {
|
||||||
operandRegExp.lastIndex = p;
|
operandRegExp.lastIndex = p;
|
||||||
match = operandRegExp.exec(filterString);
|
|
||||||
if(!match || match.index !== p) {
|
|
||||||
throw $tw.language.getString("Error/FilterSyntax");
|
|
||||||
}
|
|
||||||
var operation = {
|
var operation = {
|
||||||
prefix: "",
|
prefix: "",
|
||||||
operators: []
|
operators: []
|
||||||
};
|
};
|
||||||
if(match[1]) {
|
match = operandRegExp.exec(filterString);
|
||||||
operation.prefix = match[1];
|
if(match && match.index === p) {
|
||||||
p = p + operation.prefix.length;
|
// If there is a filter run prefix
|
||||||
if(match[2]) {
|
if(match[1]) {
|
||||||
operation.namedPrefix = match[2];
|
operation.prefix = match[1];
|
||||||
}
|
p = p + operation.prefix.length;
|
||||||
if(match[3]) {
|
// Name for named prefixes
|
||||||
operation.suffixes = [];
|
if(match[2]) {
|
||||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
operation.namedPrefix = match[2];
|
||||||
operation.suffixes.push([]);
|
}
|
||||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
// Suffixes for filter run prefix
|
||||||
entry = $tw.utils.trim(entry);
|
if(match[3]) {
|
||||||
if(entry) {
|
operation.suffixes = [];
|
||||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||||
}
|
operation.suffixes.push([]);
|
||||||
|
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||||
|
entry = $tw.utils.trim(entry);
|
||||||
|
if(entry) {
|
||||||
|
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
// Opening square bracket
|
||||||
|
if(match[4]) {
|
||||||
|
p = parseFilterOperation(operation.operators,filterString,p);
|
||||||
|
} else {
|
||||||
|
p = match.index + match[0].length;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(match[4]) { // Opening square bracket
|
|
||||||
p = parseFilterOperation(operation.operators,filterString,p);
|
|
||||||
} else {
|
} else {
|
||||||
p = match.index + match[0].length;
|
// No filter run prefix
|
||||||
|
p = parseFilterOperation(operation.operators,filterString,p);
|
||||||
}
|
}
|
||||||
|
// Quoted strings and unquoted title
|
||||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||||
operation.operators.push(
|
operation.operators.push(
|
||||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||||
@@ -213,7 +232,12 @@ exports.getFilterRunPrefixes = function() {
|
|||||||
|
|
||||||
exports.filterTiddlers = function(filterString,widget,source) {
|
exports.filterTiddlers = function(filterString,widget,source) {
|
||||||
var fn = this.compileFilter(filterString);
|
var fn = this.compileFilter(filterString);
|
||||||
return fn.call(this,source,widget);
|
try {
|
||||||
|
const fnResult = fn.call(this,source,widget);
|
||||||
|
return fnResult;
|
||||||
|
} catch(e) {
|
||||||
|
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -251,6 +275,8 @@ exports.compileFilter = function(filterString) {
|
|||||||
results = [];
|
results = [];
|
||||||
$tw.utils.each(operation.operators,function(operator) {
|
$tw.utils.each(operation.operators,function(operator) {
|
||||||
var operands = [],
|
var operands = [],
|
||||||
|
multiValueOperands = [],
|
||||||
|
isMultiValueOperand = [],
|
||||||
operatorFunction;
|
operatorFunction;
|
||||||
if(!operator.operator) {
|
if(!operator.operator) {
|
||||||
// Use the "title" operator if no operator is specified
|
// Use the "title" operator if no operator is specified
|
||||||
@@ -266,28 +292,46 @@ exports.compileFilter = function(filterString) {
|
|||||||
if(operand.indirect) {
|
if(operand.indirect) {
|
||||||
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||||
|
operand.multiValue = [operand.value];
|
||||||
} else if(operand.variable) {
|
} else if(operand.variable) {
|
||||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
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 {
|
} else {
|
||||||
operand.value = operand.text;
|
operand.value = operand.text;
|
||||||
|
operand.multiValue = [operand.value];
|
||||||
}
|
}
|
||||||
operands.push(operand.value);
|
operands.push(operand.value);
|
||||||
|
multiValueOperands.push(operand.multiValue);
|
||||||
|
isMultiValueOperand.push(!!operand.isMultiValueOperand);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Invoke the appropriate filteroperator module
|
// Invoke the appropriate filteroperator module
|
||||||
results = operatorFunction(accumulator,{
|
results = operatorFunction(accumulator,{
|
||||||
operator: operator.operator,
|
operator: operator.operator,
|
||||||
operand: operands.length > 0 ? operands[0] : undefined,
|
operand: operands.length > 0 ? operands[0] : undefined,
|
||||||
operands: operands,
|
operands: operands,
|
||||||
prefix: operator.prefix,
|
multiValueOperands: multiValueOperands,
|
||||||
suffix: operator.suffix,
|
isMultiValueOperand: isMultiValueOperand,
|
||||||
suffixes: operator.suffixes,
|
prefix: operator.prefix,
|
||||||
regexp: operator.regexp
|
suffix: operator.suffix,
|
||||||
},{
|
suffixes: operator.suffixes,
|
||||||
wiki: self,
|
regexp: operator.regexp
|
||||||
widget: widget
|
},{
|
||||||
});
|
wiki: self,
|
||||||
|
widget: widget
|
||||||
|
});
|
||||||
if($tw.utils.isArray(results)) {
|
if($tw.utils.isArray(results)) {
|
||||||
accumulator = self.makeTiddlerIterator(results);
|
accumulator = self.makeTiddlerIterator(results);
|
||||||
} else {
|
} else {
|
||||||
@@ -319,6 +363,8 @@ exports.compileFilter = function(filterString) {
|
|||||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||||
|
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||||
|
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||||
default:
|
default:
|
||||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||||
@@ -345,7 +391,13 @@ exports.compileFilter = function(filterString) {
|
|||||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||||
operationFunction(results,source,widget);
|
var operationResult = operationFunction(results,source,widget);
|
||||||
|
if(operationResult) {
|
||||||
|
if(operationResult.variables) {
|
||||||
|
// If the filter run prefix has returned variables, create a new fake widget with those variables
|
||||||
|
widget = widget.makeFakeWidgetWithVariables(operationResult.variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push("/**-- Excessive filter recursion --**/");
|
results.push("/**-- Excessive filter recursion --**/");
|
||||||
|
|||||||
@@ -16,12 +16,8 @@ exports.json = function(source,operand,options) {
|
|||||||
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||||
}
|
}
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = $tw.utils.parseJSONSafe(title);
|
var data = $tw.utils.parseJSONSafe(title,function(){return undefined;});
|
||||||
try {
|
|
||||||
data = JSON.parse(title);
|
|
||||||
} catch(e) {
|
|
||||||
data = undefined;
|
|
||||||
}
|
|
||||||
if(data !== undefined) {
|
if(data !== undefined) {
|
||||||
results.push(JSON.stringify(data,null,spaces));
|
results.push(JSON.stringify(data,null,spaces));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ exports.function = function(source,operator,options) {
|
|||||||
var functionName = operator.operands[0],
|
var functionName = operator.operands[0],
|
||||||
params = [],
|
params = [],
|
||||||
results;
|
results;
|
||||||
$tw.utils.each(operator.operands.slice(1),function(param) {
|
$tw.utils.each(operator.multiValueOperands.slice(1),function(paramList) {
|
||||||
params.push({value: param});
|
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||||
});
|
});
|
||||||
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
||||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
||||||
|
|||||||
@@ -113,6 +113,22 @@ exports["jsonset"] = function(source,operator,options) {
|
|||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports["jsondelete"] = function(source,operator,options) {
|
||||||
|
var indexes = operator.operands,
|
||||||
|
results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
|
// If parsing failed (data equals original title and is a string), return unchanged
|
||||||
|
if(data === title && typeof data === "string") {
|
||||||
|
results.push(title);
|
||||||
|
} else if(data) {
|
||||||
|
data = deleteDataItem(data,indexes);
|
||||||
|
results.push(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||||
*/
|
*/
|
||||||
@@ -144,7 +160,7 @@ function convertDataItemValueToStrings(item) {
|
|||||||
return ["null"]
|
return ["null"]
|
||||||
} else if(typeof item === "object") {
|
} else if(typeof item === "object") {
|
||||||
var results = [],i,t;
|
var results = [],i,t;
|
||||||
if($tw.utils.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
// Return all the items in arrays recursively
|
// Return all the items in arrays recursively
|
||||||
for(i=0; i<item.length; i++) {
|
for(i=0; i<item.length; i++) {
|
||||||
t = convertDataItemValueToStrings(item[i])
|
t = convertDataItemValueToStrings(item[i])
|
||||||
@@ -178,7 +194,7 @@ function convertDataItemKeysToStrings(item) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var results = [];
|
var results = [];
|
||||||
if($tw.utils.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
for(var i=0; i<item.length; i++) {
|
for(var i=0; i<item.length; i++) {
|
||||||
results.push(i.toString());
|
results.push(i.toString());
|
||||||
}
|
}
|
||||||
@@ -201,7 +217,7 @@ function getDataItemType(data,indexes) {
|
|||||||
return item;
|
return item;
|
||||||
} else if(item === null) {
|
} else if(item === null) {
|
||||||
return "null";
|
return "null";
|
||||||
} else if($tw.utils.isArray(item)) {
|
} else if(Array.isArray(item)) {
|
||||||
return "array";
|
return "array";
|
||||||
} else if(typeof item === "object") {
|
} else if(typeof item === "object") {
|
||||||
return "object";
|
return "object";
|
||||||
@@ -213,7 +229,7 @@ function getDataItemType(data,indexes) {
|
|||||||
function getItemAtIndex(item,index) {
|
function getItemAtIndex(item,index) {
|
||||||
if($tw.utils.hop(item,index)) {
|
if($tw.utils.hop(item,index)) {
|
||||||
return item[index];
|
return item[index];
|
||||||
} else if($tw.utils.isArray(item)) {
|
} else if(Array.isArray(item)) {
|
||||||
index = $tw.utils.parseInt(index);
|
index = $tw.utils.parseInt(index);
|
||||||
if(index < 0) { index = index + item.length };
|
if(index < 0) { index = index + item.length };
|
||||||
return item[index]; // Will be undefined if index was out-of-bounds
|
return item[index]; // Will be undefined if index was out-of-bounds
|
||||||
@@ -223,15 +239,16 @@ function getItemAtIndex(item,index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
Traverse the index chain and return the item at the specified depth.
|
||||||
|
Returns the item at the end of the traversal, or undefined if traversal fails.
|
||||||
*/
|
*/
|
||||||
function getDataItem(data,indexes) {
|
function traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
// Get the item
|
|
||||||
var item = data;
|
var item = data;
|
||||||
for(var i=0; i<indexes.length; i++) {
|
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
|
||||||
|
for(var i = 0; i < stopIndex; i++) {
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||||
item = getItemAtIndex(item,indexes[i]);
|
item = getItemAtIndex(item,indexes[i]);
|
||||||
@@ -243,6 +260,13 @@ function getDataItem(data,indexes) {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||||
|
*/
|
||||||
|
function getDataItem(data,indexes) {
|
||||||
|
return traverseIndexChain(data,indexes,false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
||||||
*/
|
*/
|
||||||
@@ -255,18 +279,15 @@ function setDataItem(data,indexes,value) {
|
|||||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
// Traverse the JSON data structure using the index chain
|
// Traverse the JSON data structure using the index chain up to the parent
|
||||||
var current = data;
|
var current = traverseIndexChain(data,indexes,true);
|
||||||
for(var i = 0; i < indexes.length - 1; i++) {
|
if(current === undefined) {
|
||||||
current = getItemAtIndex(current,indexes[i]);
|
// Return the original JSON data structure if any of the index strings are invalid
|
||||||
if(current === undefined) {
|
return data;
|
||||||
// Return the original JSON data structure if any of the index strings are invalid
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Add the value to the end of the index chain
|
// Add the value to the end of the index chain
|
||||||
var lastIndex = indexes[indexes.length - 1];
|
var lastIndex = indexes[indexes.length - 1];
|
||||||
if($tw.utils.isArray(current)) {
|
if(Array.isArray(current)) {
|
||||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||||
}
|
}
|
||||||
@@ -276,3 +297,32 @@ function setDataItem(data,indexes,value) {
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
|
||||||
|
*/
|
||||||
|
function deleteDataItem(data,indexes) {
|
||||||
|
// Check for the root item - don't delete the root
|
||||||
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// Traverse the JSON data structure using the index chain up to the parent
|
||||||
|
var current = traverseIndexChain(data,indexes,true);
|
||||||
|
if(current === undefined || current === null) {
|
||||||
|
// Return the original JSON data structure if any of the index strings are invalid
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// Delete the item at the end of the index chain
|
||||||
|
var lastIndex = indexes[indexes.length - 1];
|
||||||
|
if(Array.isArray(current) && current !== null) {
|
||||||
|
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||||
|
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||||
|
// Check if index is valid before splicing
|
||||||
|
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||||
|
current.splice(lastIndex,1);
|
||||||
|
}
|
||||||
|
} else if(typeof current === "object" && current !== null) {
|
||||||
|
delete current[lastIndex];
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
|||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
result.push($tw.utils.parseNumber(title));
|
result.push($tw.utils.parseNumber(title));
|
||||||
});
|
});
|
||||||
|
// We return an empty array if there are no input titles
|
||||||
|
if(result.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
var value = result.reduce(function(accumulator,currentValue) {
|
var value = result.reduce(function(accumulator,currentValue) {
|
||||||
return fnCalc(accumulator,currentValue);
|
return fnCalc(accumulator,currentValue);
|
||||||
},initialValue);
|
},initialValue);
|
||||||
|
|||||||
@@ -14,31 +14,31 @@ Export our filter function
|
|||||||
*/
|
*/
|
||||||
exports.sort = function(source,operator,options) {
|
exports.sort = function(source,operator,options) {
|
||||||
var results = prepare_results(source);
|
var results = prepare_results(source);
|
||||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
|
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.nsort = function(source,operator,options) {
|
exports.nsort = function(source,operator,options) {
|
||||||
var results = prepare_results(source);
|
var results = prepare_results(source);
|
||||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
|
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.sortan = function(source, operator, options) {
|
exports.sortan = function(source, operator, options) {
|
||||||
var results = prepare_results(source);
|
var results = prepare_results(source);
|
||||||
options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
|
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.sortcs = function(source,operator,options) {
|
exports.sortcs = function(source,operator,options) {
|
||||||
var results = prepare_results(source);
|
var results = prepare_results(source);
|
||||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
|
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.nsortcs = function(source,operator,options) {
|
exports.nsortcs = function(source,operator,options) {
|
||||||
var results = prepare_results(source);
|
var results = prepare_results(source);
|
||||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
|
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]);
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
|
|||||||
operand = (operator.operand || ""),
|
operand = (operator.operand || ""),
|
||||||
fnCalc;
|
fnCalc;
|
||||||
if(suffix === "prefix") {
|
if(suffix === "prefix") {
|
||||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
|
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];};
|
||||||
} else if(suffix === "suffix") {
|
} else if(suffix === "suffix") {
|
||||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
|
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];};
|
||||||
} else {
|
} else {
|
||||||
if(operand === "") {
|
if(operand === "") {
|
||||||
fnCalc = function(a) {return [$tw.utils.trim(a)];}
|
fnCalc = function(a) {return [$tw.utils.trim(a)];};
|
||||||
} else {
|
} else {
|
||||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
|
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
@@ -71,107 +71,53 @@ exports.join = makeStringReducingOperator(
|
|||||||
},null
|
},null
|
||||||
);
|
);
|
||||||
|
|
||||||
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||||
|
|
||||||
exports.levenshtein = makeStringBinaryOperator(
|
exports.levenshtein = makeStringBinaryOperator(
|
||||||
function(a,b) {
|
function(a,b) {
|
||||||
var dmpObject = new dmp.diff_match_patch(),
|
const diffs = dmp.diffMain(a,b);
|
||||||
diffs = dmpObject.diff_main(a,b);
|
return [dmp.diffLevenshtein(diffs).toString()];
|
||||||
return [dmpObject.diff_levenshtein(diffs) + ""];
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||||
function diffLineWordMode(text1,text2,mode) {
|
function diffLineWordMode(text1,text2,mode) {
|
||||||
var dmpObject = new dmp.diff_match_patch();
|
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
|
||||||
var a = diffPartsToChars(text1,text2,mode);
|
|
||||||
var lineText1 = a.chars1;
|
var lineText1 = a.chars1;
|
||||||
var lineText2 = a.chars2;
|
var lineText2 = a.chars2;
|
||||||
var lineArray = a.lineArray;
|
var lineArray = a.lineArray;
|
||||||
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
var diffs = dmp.diffMain(lineText1,lineText2,false);
|
||||||
dmpObject.diff_charsToLines_(diffs,lineArray);
|
dmp.diffCharsToLines(diffs,lineArray);
|
||||||
return diffs;
|
return diffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function diffPartsToChars(text1,text2,mode) {
|
|
||||||
var lineArray = [];
|
|
||||||
var lineHash = {};
|
|
||||||
lineArray[0] = '';
|
|
||||||
|
|
||||||
function diff_linesToPartsMunge_(text,mode) {
|
|
||||||
var chars = '';
|
|
||||||
var lineStart = 0;
|
|
||||||
var lineEnd = -1;
|
|
||||||
var lineArrayLength = lineArray.length,
|
|
||||||
regexpResult;
|
|
||||||
var searchRegexp = /\W+/g;
|
|
||||||
while(lineEnd < text.length - 1) {
|
|
||||||
if(mode === "words") {
|
|
||||||
regexpResult = searchRegexp.exec(text);
|
|
||||||
lineEnd = searchRegexp.lastIndex;
|
|
||||||
if(regexpResult === null) {
|
|
||||||
lineEnd = text.length;
|
|
||||||
}
|
|
||||||
lineEnd = --lineEnd;
|
|
||||||
} else {
|
|
||||||
lineEnd = text.indexOf('\n', lineStart);
|
|
||||||
if(lineEnd == -1) {
|
|
||||||
lineEnd = text.length - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var line = text.substring(lineStart, lineEnd + 1);
|
|
||||||
|
|
||||||
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
|
||||||
chars += String.fromCharCode(lineHash[line]);
|
|
||||||
} else {
|
|
||||||
if(lineArrayLength == maxLines) {
|
|
||||||
line = text.substring(lineStart);
|
|
||||||
lineEnd = text.length;
|
|
||||||
}
|
|
||||||
chars += String.fromCharCode(lineArrayLength);
|
|
||||||
lineHash[line] = lineArrayLength;
|
|
||||||
lineArray[lineArrayLength++] = line;
|
|
||||||
}
|
|
||||||
lineStart = lineEnd + 1;
|
|
||||||
}
|
|
||||||
return chars;
|
|
||||||
}
|
|
||||||
var maxLines = 40000;
|
|
||||||
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
|
||||||
maxLines = 65535;
|
|
||||||
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
|
||||||
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.makepatches = function(source,operator,options) {
|
exports.makepatches = function(source,operator,options) {
|
||||||
var dmpObject = new dmp.diff_match_patch(),
|
var suffix = operator.suffix || "",
|
||||||
suffix = operator.suffix || "",
|
|
||||||
result = [];
|
result = [];
|
||||||
|
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var diffs, patches;
|
let diffs, patches;
|
||||||
if(suffix === "lines" || suffix === "words") {
|
if(suffix === "lines" || suffix === "words") {
|
||||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||||
patches = dmpObject.patch_make(title,diffs);
|
patches = dmp.patchMake(title,diffs);
|
||||||
} else {
|
} else {
|
||||||
patches = dmpObject.patch_make(title,operator.operand);
|
patches = dmp.patchMake(title,operator.operand);
|
||||||
}
|
}
|
||||||
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.applypatches = makeStringBinaryOperator(
|
exports.applypatches = makeStringBinaryOperator(
|
||||||
function(a,b) {
|
function(a,b) {
|
||||||
var dmpObject = new dmp.diff_match_patch(),
|
let patches;
|
||||||
patches;
|
|
||||||
try {
|
try {
|
||||||
patches = dmpObject.patch_fromText(b);
|
patches = dmp.patchFromText(b);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
}
|
}
|
||||||
if(patches) {
|
if(patches) {
|
||||||
return [dmpObject.patch_apply(patches,a)[0]];
|
return [dmp.patchApply(patches,a)[0]];
|
||||||
} else {
|
} else {
|
||||||
return [a];
|
return [a];
|
||||||
}
|
}
|
||||||
@@ -279,7 +225,7 @@ exports.pad = function(source,operator,options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.charcode = function(source,operator,options) {
|
exports.charcode = function(source,operator,options) {
|
||||||
var chars = [];
|
var chars = [];
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ exports.title = function(source,operator,options) {
|
|||||||
var results = [];
|
var results = [];
|
||||||
if(operator.prefix === "!") {
|
if(operator.prefix === "!") {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(tiddler && tiddler.fields.title !== operator.operand) {
|
var titleList = operator.multiValueOperands[0] || [];
|
||||||
|
if(tiddler && titleList.indexOf(tiddler.fields.title) === -1) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push(operator.operand);
|
Array.prototype.push.apply(results,operator.multiValueOperands[0]);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ exports["[unknown]"] = function(source,operator,options) {
|
|||||||
// Check for a user defined filter operator
|
// Check for a user defined filter operator
|
||||||
if(operator.operator.indexOf(".") !== -1) {
|
if(operator.operator.indexOf(".") !== -1) {
|
||||||
var params = [];
|
var params = [];
|
||||||
$tw.utils.each(operator.operands,function(param) {
|
$tw.utils.each(operator.multiValueOperands,function(paramList) {
|
||||||
params.push({value: param});
|
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||||
});
|
});
|
||||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
|
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
|
||||||
if(variableInfo && variableInfo.srcVariable) {
|
if(variableInfo && variableInfo.srcVariable) {
|
||||||
|
|||||||
86
core/modules/info/dimensions.js
Normal file
86
core/modules/info/dimensions.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*\
|
||||||
|
title: $:/core/modules/info/windowdimensions.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: info
|
||||||
|
\*/
|
||||||
|
|
||||||
|
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||||
|
if(!$tw.browser) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindowDimensionsTracker {
|
||||||
|
constructor(updateCallback) {
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
this.resizeHandlers = new Map();
|
||||||
|
this.dimensionsInfo = [
|
||||||
|
["outer/width", win => win.outerWidth],
|
||||||
|
["outer/height", win => win.outerHeight],
|
||||||
|
["inner/width", win => win.innerWidth],
|
||||||
|
["inner/height", win => win.innerHeight],
|
||||||
|
["client/width", win => win.document.documentElement.clientWidth],
|
||||||
|
["client/height", win => win.document.documentElement.clientHeight]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTiddlers(win,windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`;
|
||||||
|
return this.dimensionsInfo.map(([suffix, getter]) => ({
|
||||||
|
title: prefix + suffix,
|
||||||
|
text: String(getter(win))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTiddlers(windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`,
|
||||||
|
deletions = this.dimensionsInfo.map(([suffix]) => prefix + suffix);
|
||||||
|
this.updateCallback([], deletions);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdateHandler(win,windowId) {
|
||||||
|
let scheduled = false;
|
||||||
|
return () => {
|
||||||
|
if(!scheduled) {
|
||||||
|
scheduled = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.updateCallback(this.buildTiddlers(win,windowId), []);
|
||||||
|
scheduled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trackWindow(win,windowId) {
|
||||||
|
const handler = this.getUpdateHandler(win, windowId);
|
||||||
|
handler(); // initial update
|
||||||
|
win.addEventListener("resize",handler,{passive:true});
|
||||||
|
this.resizeHandlers.set(windowId,{win, handler});
|
||||||
|
}
|
||||||
|
|
||||||
|
untrackWindow(windowId) {
|
||||||
|
const entry = this.resizeHandlers.get(windowId);
|
||||||
|
if(entry) {
|
||||||
|
entry.win.removeEventListener("resize", entry.handler);
|
||||||
|
this.resizeHandlers.delete(windowId);
|
||||||
|
}
|
||||||
|
this.clearTiddlers(windowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tracker = new WindowDimensionsTracker(updateInfoTiddlersCallback);
|
||||||
|
|
||||||
|
// Track main window
|
||||||
|
tracker.trackWindow(window,"system/main");
|
||||||
|
|
||||||
|
// Hook into event bus for user windows
|
||||||
|
if($tw.eventBus) {
|
||||||
|
$tw.eventBus.on("window:opened", ({window: win, windowID}) => {
|
||||||
|
tracker.trackWindow(win, "user/" + windowID);
|
||||||
|
});
|
||||||
|
$tw.eventBus.on("window:closed", ({windowID}) => {
|
||||||
|
tracker.untrackWindow("user/" + windowID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
@@ -7,23 +7,34 @@ The audio parser parses an audio tiddler into an embeddable HTML element
|
|||||||
|
|
||||||
\*/
|
\*/
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AudioParser = function(type,text,options) {
|
var AudioParser = function(type,text,options) {
|
||||||
var element = {
|
var element = {
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "audio",
|
tag: "$audio", // Using $audio to enable widget interception
|
||||||
attributes: {
|
attributes: {
|
||||||
controls: {type: "string", value: "controls"},
|
controls: {type: "string", value: "controls"},
|
||||||
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
style: {type: "string", value: "width: 100%; object-fit: contain"}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
src;
|
|
||||||
|
// Pass through source information
|
||||||
if(options._canonical_uri) {
|
if(options._canonical_uri) {
|
||||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
element.attributes.src = {type: "string", value: options._canonical_uri};
|
||||||
|
element.attributes.type = {type: "string", value: type};
|
||||||
} else if(text) {
|
} else if(text) {
|
||||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
||||||
|
element.attributes.type = {type: "string", value: type};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass through tiddler title if available
|
||||||
|
if(options.title) {
|
||||||
|
element.attributes.tiddler = {type: "string", value: options.title};
|
||||||
|
}
|
||||||
|
|
||||||
this.tree = [element];
|
this.tree = [element];
|
||||||
this.source = text;
|
this.source = text;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@@ -33,3 +44,4 @@ exports["audio/ogg"] = AudioParser;
|
|||||||
exports["audio/mpeg"] = AudioParser;
|
exports["audio/mpeg"] = AudioParser;
|
||||||
exports["audio/mp3"] = AudioParser;
|
exports["audio/mp3"] = AudioParser;
|
||||||
exports["audio/mp4"] = AudioParser;
|
exports["audio/mp4"] = AudioParser;
|
||||||
|
|
||||||
@@ -11,10 +11,13 @@ The CSV text parser processes CSV files into a table wrapped in a scrollable wid
|
|||||||
|
|
||||||
var CsvParser = function(type,text,options) {
|
var CsvParser = function(type,text,options) {
|
||||||
// Special handler for tab-delimited files
|
// Special handler for tab-delimited files
|
||||||
if (type === 'text/tab-delimited-values' && !options.separator) {
|
if(
|
||||||
|
!options.separator &&
|
||||||
|
(type === "text/tab-delimited-values" || type === "text/tab-separated-values")
|
||||||
|
) {
|
||||||
options.separator = "\t";
|
options.separator = "\t";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Table framework
|
// Table framework
|
||||||
this.tree = [{
|
this.tree = [{
|
||||||
"type": "scrollable", "children": [{
|
"type": "scrollable", "children": [{
|
||||||
@@ -32,7 +35,7 @@ var CsvParser = function(type,text,options) {
|
|||||||
$tw.utils.each(lines, function(columns) {
|
$tw.utils.each(lines, function(columns) {
|
||||||
maxColumns = Math.max(columns.length, maxColumns);
|
maxColumns = Math.max(columns.length, maxColumns);
|
||||||
});
|
});
|
||||||
|
|
||||||
for(var line=0; line<lines.length; line++) {
|
for(var line=0; line<lines.length; line++) {
|
||||||
var columns = lines[line];
|
var columns = lines[line];
|
||||||
var row = {
|
var row = {
|
||||||
@@ -55,3 +58,4 @@ var CsvParser = function(type,text,options) {
|
|||||||
|
|
||||||
exports["text/csv"] = CsvParser;
|
exports["text/csv"] = CsvParser;
|
||||||
exports["text/tab-delimited-values"] = CsvParser;
|
exports["text/tab-delimited-values"] = CsvParser;
|
||||||
|
exports["text/tab-separated-values"] = CsvParser;
|
||||||
|
|||||||
@@ -11,17 +11,16 @@ The image parser parses an image into an embeddable HTML element
|
|||||||
|
|
||||||
var ImageParser = function(type,text,options) {
|
var ImageParser = function(type,text,options) {
|
||||||
var element = {
|
var element = {
|
||||||
type: "element",
|
type: "image",
|
||||||
tag: "img",
|
attributes: {}
|
||||||
attributes: {}
|
};
|
||||||
};
|
|
||||||
if(options._canonical_uri) {
|
if(options._canonical_uri) {
|
||||||
element.attributes.src = {type: "string", value: options._canonical_uri};
|
element.attributes.source = {type: "string", value: options._canonical_uri};
|
||||||
} else if(text) {
|
} else if(text) {
|
||||||
if(type === "image/svg+xml" || type === ".svg") {
|
if(type === "image/svg+xml" || type === ".svg") {
|
||||||
element.attributes.src = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
element.attributes.source = {type: "string", value: "data:image/svg+xml," + encodeURIComponent(text)};
|
||||||
} else {
|
} else {
|
||||||
element.attributes.src = {type: "string", value: "data:" + type + ";base64," + text};
|
element.attributes.source = {type: "string", value: "data:" + type + ";base64," + text};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.tree = [element];
|
this.tree = [element];
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ exports.parseTokenString = function(source,pos,token) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
Look for a token matching a regex. Returns null if not found, otherwise returns {type: "regexp", match:, start:, end:,}
|
||||||
|
Use the "Y" (sticky) flag to avoid searching the entire rest of the string
|
||||||
*/
|
*/
|
||||||
exports.parseTokenRegExp = function(source,pos,reToken) {
|
exports.parseTokenRegExp = function(source,pos,reToken) {
|
||||||
var node = {
|
var node = {
|
||||||
@@ -172,7 +173,7 @@ exports.parseMacroParameter = function(source,pos) {
|
|||||||
start: pos
|
start: pos
|
||||||
};
|
};
|
||||||
// Define our regexp
|
// Define our regexp
|
||||||
var reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/g;
|
const reMacroParameter = /(?:([A-Za-z0-9\-_]+)\s*:)?(?:\s*(?:"""([\s\S]*?)"""|"([^"]*)"|'([^']*)'|\[\[([^\]]*)\]\]|((?:(?:>(?!>))|[^\s>"'])+)))/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for the parameter
|
// Look for the parameter
|
||||||
@@ -240,7 +241,7 @@ exports.parseMacroInvocation = function(source,pos) {
|
|||||||
params: []
|
params: []
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reMacroName = /([^\s>"'=]+)/g;
|
const reMacroName = /([^\s>"'=]+)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for a double less than sign
|
// Look for a double less than sign
|
||||||
@@ -277,7 +278,7 @@ exports.parseFilterVariable = function(source) {
|
|||||||
params: [],
|
params: [],
|
||||||
},
|
},
|
||||||
pos = 0,
|
pos = 0,
|
||||||
reName = /([^\s"']+)/g;
|
reName = /([^\s"']+)/y;
|
||||||
// If there is no whitespace or it is an empty string then there are no macro parameters
|
// If there is no whitespace or it is an empty string then there are no macro parameters
|
||||||
if(/^\S*$/.test(source)) {
|
if(/^\S*$/.test(source)) {
|
||||||
node.name = source;
|
node.name = source;
|
||||||
@@ -302,11 +303,11 @@ exports.parseAttribute = function(source,pos) {
|
|||||||
start: pos
|
start: pos
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reAttributeName = /([^\/\s>"'`=]+)/g,
|
const reAttributeName = /([^\/\s>"'`=]+)/y,
|
||||||
reUnquotedAttribute = /([^\/\s<>"'`=]+)/g,
|
reUnquotedAttribute = /([^\/\s<>"'`=]+)/y,
|
||||||
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/g,
|
reFilteredValue = /\{\{\{([\S\s]+?)\}\}\}/y,
|
||||||
reIndirectValue = /\{\{([^\}]+)\}\}/g,
|
reIndirectValue = /\{\{([^\}]+)\}\}/y,
|
||||||
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/g;
|
reSubstitutedValue = /(?:```([\s\S]*?)```|`([^`]|[\S\s]*?)`)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Get the attribute name
|
// Get the attribute name
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Note that the syntax for comments is simplified to an opening "<!--" sequence an
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.name = "commentblock";
|
exports.name = "commentblock";
|
||||||
exports.types = {block:true, pragma:true};
|
exports.types = {block: true, pragma: true};
|
||||||
|
|
||||||
exports.init = function(parser) {
|
exports.init = function(parser) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
@@ -43,9 +43,18 @@ exports.findNextMatch = function(startPos) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.endMatchRegExp.lastIndex;
|
this.parser.pos = this.endMatchRegExp.lastIndex;
|
||||||
// Don't return any elements
|
// Return a node representing the comment that is not rendered
|
||||||
return [];
|
var commentStart = this.match.index;
|
||||||
|
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||||
|
return [{
|
||||||
|
type: "void",
|
||||||
|
children: [],
|
||||||
|
text: this.parser.source.slice(commentStart, commentEnd),
|
||||||
|
start: commentStart,
|
||||||
|
end: commentEnd
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ exports.findNextMatch = function(startPos) {
|
|||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
this.parser.pos = this.endMatchRegExp.lastIndex;
|
this.parser.pos = this.endMatchRegExp.lastIndex;
|
||||||
// Don't return any elements
|
// Return a node representing the inline comment
|
||||||
return [];
|
var commentStart = this.match.index;
|
||||||
|
var commentEnd = this.endMatch.index + this.endMatch[0].length;
|
||||||
|
return [{
|
||||||
|
type: "void",
|
||||||
|
text: this.parser.source.slice(commentStart, commentEnd),
|
||||||
|
start: commentStart,
|
||||||
|
end: commentEnd
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ exports.parse = function() {
|
|||||||
// Return the classed span
|
// Return the classed span
|
||||||
return [{
|
return [{
|
||||||
type: "element",
|
type: "element",
|
||||||
tag: "strike",
|
tag: "s",
|
||||||
children: tree
|
children: tree
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ exports.init = function(parser) {
|
|||||||
|
|
||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Move past the match
|
// Move past the match
|
||||||
var start = this.parser.pos;
|
var start = this.parser.pos;
|
||||||
this.parser.pos = this.matchRegExp.lastIndex;
|
this.parser.pos = this.matchRegExp.lastIndex;
|
||||||
// Create the link unless it is suppressed
|
// Create the link unless it is suppressed
|
||||||
if(this.match[0].substr(0,1) === "~") {
|
if(this.match[0].substr(0,1) === "~") {
|
||||||
return [{type: "text", text: this.match[0].substr(1)}];
|
return [{type: "text", text: this.match[0].substr(1), start: start, end: this.parser.pos}];
|
||||||
} else {
|
} else {
|
||||||
return [{
|
return [{
|
||||||
type: "element",
|
type: "element",
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ module-type: wikirule
|
|||||||
Wiki pragma rule for function, procedure and widget definitions
|
Wiki pragma rule for function, procedure and widget definitions
|
||||||
|
|
||||||
```
|
```
|
||||||
\function name(param:defaultvalue,param2:defaultvalue)
|
\function name(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
|
|
||||||
\procedure name(param:defaultvalue,param2:defaultvalue)
|
\procedure name(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
|
|
||||||
\widget $mywidget(param:defaultvalue,param2:defaultvalue)
|
\widget $mywidget(param:"defaultvalue", param2:"defaultvalue")
|
||||||
definition text
|
definition text
|
||||||
\end
|
\end
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ exports.parse = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while(match && !match[1]);
|
} while(match && !match[1]);
|
||||||
// Return the nodes
|
// Mark first and last node, and return the nodes
|
||||||
|
if(tree[0]) tree[0].isRuleStart = true;
|
||||||
|
if(tree[tree.length-1]) tree[tree.length-1].isRuleEnd = true;
|
||||||
return tree;
|
return tree;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ Parse the most recent match
|
|||||||
exports.parse = function() {
|
exports.parse = function() {
|
||||||
// Retrieve the most recent match so that recursive calls don't overwrite it
|
// Retrieve the most recent match so that recursive calls don't overwrite it
|
||||||
var tag = this.nextTag;
|
var tag = this.nextTag;
|
||||||
if (!tag.isSelfClosing) {
|
if(!tag.isSelfClosing) {
|
||||||
tag.openTagStart = tag.start;
|
tag.openTagStart = tag.start;
|
||||||
tag.openTagEnd = tag.end;
|
tag.openTagEnd = tag.end;
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ exports.parse = function() {
|
|||||||
// Advance the parser position to past the tag
|
// Advance the parser position to past the tag
|
||||||
this.parser.pos = tag.end;
|
this.parser.pos = tag.end;
|
||||||
// Check for an immediately following double linebreak
|
// Check for an immediately following double linebreak
|
||||||
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
var hasLineBreak = !tag.isSelfClosing && !!$tw.utils.parseTokenRegExp(this.parser.source,this.parser.pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||||
// Set whether we're in block mode
|
// Set whether we're in block mode
|
||||||
tag.isBlock = this.is.block || hasLineBreak;
|
tag.isBlock = this.is.block || hasLineBreak;
|
||||||
// Parse the body if we need to
|
// Parse the body if we need to
|
||||||
@@ -63,22 +63,22 @@ exports.parse = function() {
|
|||||||
}
|
}
|
||||||
tag.end = this.parser.pos;
|
tag.end = this.parser.pos;
|
||||||
tag.closeTagEnd = tag.end;
|
tag.closeTagEnd = tag.end;
|
||||||
if (tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== '>') {
|
if(tag.closeTagEnd === tag.openTagEnd || this.parser.source[tag.closeTagEnd - 1] !== ">") {
|
||||||
tag.closeTagStart = tag.end;
|
tag.closeTagStart = tag.end;
|
||||||
} else {
|
} else {
|
||||||
tag.closeTagStart = tag.closeTagEnd - 2;
|
tag.closeTagStart = tag.closeTagEnd - 2;
|
||||||
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
|
var closeTagMinPos = tag.children.length > 0 ? tag.children[tag.children.length-1].end : tag.openTagEnd;
|
||||||
if (!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
|
if(!Number.isSafeInteger(closeTagMinPos)) closeTagMinPos = tag.openTagEnd;
|
||||||
while (tag.closeTagStart >= closeTagMinPos) {
|
while(tag.closeTagStart >= closeTagMinPos) {
|
||||||
var char = this.parser.source[tag.closeTagStart];
|
var char = this.parser.source[tag.closeTagStart];
|
||||||
if (char === '>') {
|
if(char === ">") {
|
||||||
tag.closeTagStart = -1;
|
tag.closeTagStart = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (char === '<') break;
|
if(char === "<") break;
|
||||||
tag.closeTagStart -= 1;
|
tag.closeTagStart -= 1;
|
||||||
}
|
}
|
||||||
if (tag.closeTagStart < closeTagMinPos) {
|
if(tag.closeTagStart < closeTagMinPos) {
|
||||||
tag.closeTagStart = tag.end;
|
tag.closeTagStart = tag.end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,7 +100,7 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
orderedAttributes: []
|
orderedAttributes: []
|
||||||
};
|
};
|
||||||
// Define our regexps
|
// Define our regexps
|
||||||
var reTagName = /([a-zA-Z0-9\-\$\.]+)/g;
|
const reTagName = /([a-zA-Z0-9\-\$\.]+)/y;
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
pos = $tw.utils.skipWhiteSpace(source,pos);
|
pos = $tw.utils.skipWhiteSpace(source,pos);
|
||||||
// Look for a less than sign
|
// Look for a less than sign
|
||||||
@@ -148,7 +148,7 @@ exports.parseTag = function(source,pos,options) {
|
|||||||
pos = token.end;
|
pos = token.end;
|
||||||
// Check for a required line break
|
// Check for a required line break
|
||||||
if(options.requireLineBreak) {
|
if(options.requireLineBreak) {
|
||||||
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/g);
|
token = $tw.utils.parseTokenRegExp(source,pos,/([^\S\n\r]*\r?\n(?:[^\S\n\r]*\r?\n|$))/y);
|
||||||
if(!token) {
|
if(!token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user