mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-23 19:34:39 +00:00
Compare commits
10 Commits
default-pr
...
dynamic-bu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4022532455 | ||
|
|
b2b00324c2 | ||
|
|
e3714929f9 | ||
|
|
b31e2cd0db | ||
|
|
8b2afd1cc2 | ||
|
|
bd86723b72 | ||
|
|
2d89228d25 | ||
|
|
5233d72642 | ||
|
|
4a6501778a | ||
|
|
50118dbe13 |
317
.eslintrc.json
Normal file
317
.eslintrc.json
Normal file
@@ -0,0 +1,317 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended"
|
||||
],
|
||||
"globals": {
|
||||
"$tw": "writable"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5
|
||||
},
|
||||
"plugins": [],
|
||||
"rules": {
|
||||
"array-bracket-newline": "off",
|
||||
"array-bracket-spacing": "off",
|
||||
"array-callback-return": "off",
|
||||
"array-element-newline": "off",
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": [
|
||||
"error",
|
||||
"as-needed"
|
||||
],
|
||||
"arrow-spacing": [
|
||||
"error",
|
||||
{
|
||||
"after": true,
|
||||
"before": true
|
||||
}
|
||||
],
|
||||
"block-scoped-var": "off",
|
||||
"block-spacing": "off",
|
||||
"brace-style": "off",
|
||||
"callback-return": "off",
|
||||
"camelcase": "off",
|
||||
"capitalized-comments": "off",
|
||||
"class-methods-use-this": "error",
|
||||
"comma-dangle": "off",
|
||||
"comma-spacing": "off",
|
||||
"comma-style": "off",
|
||||
"complexity": "off",
|
||||
"computed-property-spacing": "off",
|
||||
"consistent-return": "off",
|
||||
"consistent-this": "off",
|
||||
"curly": "off",
|
||||
"default-case": "off",
|
||||
"default-case-last": "error",
|
||||
"default-param-last": "error",
|
||||
"dot-location": "off",
|
||||
"dot-notation": "off",
|
||||
"eol-last": "off",
|
||||
"eqeqeq": "off",
|
||||
"func-call-spacing": "off",
|
||||
"func-name-matching": "off",
|
||||
"func-names": "off",
|
||||
"func-style": "off",
|
||||
"function-call-argument-newline": "off",
|
||||
"function-paren-newline": "off",
|
||||
"generator-star-spacing": "error",
|
||||
"global-require": "off",
|
||||
"grouped-accessor-pairs": "error",
|
||||
"guard-for-in": "off",
|
||||
"handle-callback-err": "off",
|
||||
"id-blacklist": "error",
|
||||
"id-denylist": "error",
|
||||
"id-length": "off",
|
||||
"id-match": "error",
|
||||
"implicit-arrow-linebreak": "error",
|
||||
"indent": "off",
|
||||
"indent-legacy": "off",
|
||||
"init-declarations": "off",
|
||||
"jsx-quotes": "error",
|
||||
"key-spacing": "off",
|
||||
"keyword-spacing": [
|
||||
"error",
|
||||
{
|
||||
"before": true,
|
||||
"after": false,
|
||||
"overrides": {
|
||||
"case": {
|
||||
"after": true
|
||||
},
|
||||
"do": {
|
||||
"after": true
|
||||
},
|
||||
"else": {
|
||||
"after": true
|
||||
},
|
||||
"return": {
|
||||
"after": true
|
||||
},
|
||||
"throw": {
|
||||
"after": true
|
||||
},
|
||||
"try": {
|
||||
"after": true
|
||||
},
|
||||
"catch": {
|
||||
"after": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"line-comment-position": "off",
|
||||
"linebreak-style": "off",
|
||||
"lines-around-comment": "off",
|
||||
"lines-around-directive": "off",
|
||||
"lines-between-class-members": "error",
|
||||
"max-classes-per-file": "error",
|
||||
"max-depth": "off",
|
||||
"max-len": "off",
|
||||
"max-lines": "off",
|
||||
"max-lines-per-function": "off",
|
||||
"max-nested-callbacks": "error",
|
||||
"max-params": "off",
|
||||
"max-statements": "off",
|
||||
"max-statements-per-line": "off",
|
||||
"multiline-comment-style": "off",
|
||||
"multiline-ternary": "off",
|
||||
"new-parens": "off",
|
||||
"newline-after-var": "off",
|
||||
"newline-before-return": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"no-alert": "off",
|
||||
"no-array-constructor": "off",
|
||||
"no-await-in-loop": "error",
|
||||
"no-bitwise": "off",
|
||||
"no-buffer-constructor": "off",
|
||||
"no-caller": "error",
|
||||
"no-catch-shadow": "off",
|
||||
"no-confusing-arrow": "error",
|
||||
"no-console": "off",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-constructor-return": "error",
|
||||
"no-continue": "off",
|
||||
"no-div-regex": "off",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-else-return": "off",
|
||||
"no-empty-function": "off",
|
||||
"no-eq-null": "off",
|
||||
"no-eval": "off",
|
||||
"no-extend-native": "off",
|
||||
"no-extra-bind": "off",
|
||||
"no-extra-label": "off",
|
||||
"no-extra-parens": "off",
|
||||
"no-floating-decimal": "off",
|
||||
"no-implicit-coercion": [
|
||||
"error",
|
||||
{
|
||||
"boolean": false,
|
||||
"number": false,
|
||||
"string": false
|
||||
}
|
||||
],
|
||||
"no-implicit-globals": "off",
|
||||
"no-implied-eval": "error",
|
||||
"no-inline-comments": "off",
|
||||
"no-invalid-this": "off",
|
||||
"no-iterator": "error",
|
||||
"no-label-var": "off",
|
||||
"no-labels": "off",
|
||||
"no-lone-blocks": "off",
|
||||
"no-lonely-if": "off",
|
||||
"no-loop-func": "off",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-magic-numbers": "off",
|
||||
"no-mixed-operators": "off",
|
||||
"no-mixed-requires": "off",
|
||||
"no-multi-assign": "off",
|
||||
"no-multi-spaces": "off",
|
||||
"no-multi-str": "error",
|
||||
"no-multiple-empty-lines": ["warn", { "max": 4, "maxEOF": 0 }],
|
||||
"no-native-reassign": "off",
|
||||
"no-negated-condition": "off",
|
||||
"no-negated-in-lhs": "error",
|
||||
"no-nested-ternary": "off",
|
||||
"no-new": "off",
|
||||
"no-new-func": "off",
|
||||
"no-new-object": "off",
|
||||
"no-new-require": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-param-reassign": "off",
|
||||
"no-path-concat": "error",
|
||||
"no-plusplus": "off",
|
||||
"no-process-env": "off",
|
||||
"no-process-exit": "off",
|
||||
"no-promise-executor-return": "error",
|
||||
"no-proto": "off",
|
||||
"no-restricted-exports": "error",
|
||||
"no-restricted-globals": "error",
|
||||
"no-restricted-imports": "error",
|
||||
"no-restricted-modules": "error",
|
||||
"no-restricted-properties": "error",
|
||||
"no-restricted-syntax": "error",
|
||||
"no-return-assign": "off",
|
||||
"no-return-await": "error",
|
||||
"no-script-url": "off",
|
||||
"no-self-compare": "off",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-spaced-func": "off",
|
||||
"no-sync": "off",
|
||||
"no-tabs": "off",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-ternary": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-undef-init": "off",
|
||||
"no-undefined": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-unmodified-loop-condition": "off",
|
||||
"no-unneeded-ternary": "off",
|
||||
"no-unreachable-loop": "error",
|
||||
"no-unused-expressions": "off",
|
||||
"no-use-before-define": "off",
|
||||
"no-useless-backreference": "error",
|
||||
"no-useless-call": "off",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-concat": "off",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-rename": "error",
|
||||
"no-useless-return": "off",
|
||||
"no-var": "off",
|
||||
"no-void": "off",
|
||||
"no-warning-comments": "off",
|
||||
"no-whitespace-before-property": "error",
|
||||
"nonblock-statement-body-position": [
|
||||
"error",
|
||||
"any"
|
||||
],
|
||||
"object-curly-newline": "off",
|
||||
"object-curly-spacing": "off",
|
||||
"object-property-newline": "off",
|
||||
"object-shorthand": "off",
|
||||
"one-var": "off",
|
||||
"one-var-declaration-per-line": "off",
|
||||
"operator-assignment": "off",
|
||||
"operator-linebreak": "off",
|
||||
"padded-blocks": "off",
|
||||
"padding-line-between-statements": "error",
|
||||
"prefer-arrow-callback": "off",
|
||||
"prefer-const": "off",
|
||||
"prefer-destructuring": "off",
|
||||
"prefer-exponentiation-operator": "off",
|
||||
"prefer-named-capture-group": "off",
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-object-spread": "off",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-reflect": "off",
|
||||
"prefer-regex-literals": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"prefer-spread": "off",
|
||||
"prefer-template": "off",
|
||||
"quote-props": "off",
|
||||
"quotes": "off",
|
||||
"radix": "off",
|
||||
"require-atomic-updates": "error",
|
||||
"require-await": "error",
|
||||
"require-jsdoc": "off",
|
||||
"require-unicode-regexp": "off",
|
||||
"rest-spread-spacing": "error",
|
||||
"semi": "off",
|
||||
"semi-spacing": "off",
|
||||
"semi-style": "off",
|
||||
"sort-imports": "error",
|
||||
"sort-keys": "off",
|
||||
"sort-vars": "off",
|
||||
"space-before-blocks": "off",
|
||||
"space-before-function-paren": "off",
|
||||
"space-in-parens": "off",
|
||||
"space-infix-ops": "off",
|
||||
"space-unary-ops": "off",
|
||||
"spaced-comment": "off",
|
||||
"strict": "off",
|
||||
"switch-colon-spacing": "off",
|
||||
"symbol-description": "error",
|
||||
"template-curly-spacing": "error",
|
||||
"template-tag-spacing": "error",
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"valid-jsdoc": "off",
|
||||
"valid-typeof": [
|
||||
"error",
|
||||
{
|
||||
"requireStringLiterals": false
|
||||
}
|
||||
],
|
||||
"vars-on-top": "off",
|
||||
"wrap-iife": "off",
|
||||
"wrap-regex": "off",
|
||||
"yield-star-spacing": "error",
|
||||
"yoda": "off",
|
||||
"no-useless-escape": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-empty": "off",
|
||||
"no-extra-semi": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-control-regex": "off",
|
||||
"no-mixed-spaces-and-tabs": "off",
|
||||
"no-extra-boolean-cast": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-undef": "off",
|
||||
"no-unreachable": "off",
|
||||
"no-self-assign": "off"
|
||||
}
|
||||
}
|
||||
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -1,4 +0,0 @@
|
||||
boot/** -linguist-generated
|
||||
**/tiddlywiki.files linguist-language=JSON
|
||||
**/tiddlywiki.info linguist-language=JSON
|
||||
**/plugin.info linguist-language=JSON
|
||||
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
62
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,62 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[Report] "
|
||||
type: report
|
||||
|
||||
---
|
||||
|
||||
<!-- Remove elements, that you do not need -->
|
||||
<!-- Add screenshots where needed -->
|
||||
|
||||
**Problem Description**
|
||||
<!-- Describe your problem: A clear and concise description of what your problem is -->
|
||||
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. At https://tiddlywiki.com
|
||||
2. Click on ...
|
||||
3. Scroll down to ...
|
||||
4. See ...
|
||||
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
As a user,
|
||||
<!-- As a developer, -->
|
||||
I would expect ...
|
||||
|
||||
|
||||
**TiddlyWiki Configuration**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Report created with: [Wiki Information](https://tiddlywiki.com/#%24%3A%2Fcore%2Fui%2FControlPanel%2FWikiInformation)
|
||||
|
||||
<!-- Your report comes here -->
|
||||
<!-- or -->
|
||||
<!-- Add it manually -->
|
||||
|
||||
- Version: <!-- e.g. v5.3.8 -->
|
||||
- Saving mechanism: <!-- e.g. Node.js, TiddlyDesktop, TiddlyHost etc -->
|
||||
- Plugins installed: <!-- e.g. Freelinks, TiddlyMap ... other 3rd party plugins -->
|
||||
|
||||
|
||||
**Desktop**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- OS: <!-- e.g. iOS -->
|
||||
- Browser: <!-- e.g. chrome, safari, FireFox -- Version: -->
|
||||
|
||||
**Smartphone**
|
||||
<!-- Please complete the following information -->
|
||||
|
||||
- Device: <!-- e.g. iPhone6 -->
|
||||
- OS: <!-- e.g. iOS8.1 -->
|
||||
- Browser: <!-- e.g. stock browser, safari, FireFox -- Version: -->
|
||||
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context about the problem here. -->
|
||||
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
67
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve TiddlyWiki 5
|
||||
title: "[BUG] "
|
||||
body:
|
||||
- type: textarea
|
||||
id: Describe
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: Expected
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Reproduce
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: "Steps to reproduce the behavior:"
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
placeholder: Drag image here to upload screenshot!
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: Configuration
|
||||
attributes:
|
||||
label: TiddlyWiki Configuration
|
||||
description: please complete the following information
|
||||
placeholder: |
|
||||
- Version [e.g. v5.1.24]
|
||||
- Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]
|
||||
- Plugins installed [e.g. Freelinks, TiddlyMap]
|
||||
|
||||
### Desktop (please complete the following information):
|
||||
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
### Smartphone (please complete the following information):
|
||||
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: Context
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -4,23 +4,17 @@ about: Suggest an idea for TiddlyWiki 5
|
||||
title: "[IDEA]"
|
||||
labels: ''
|
||||
assignees: ''
|
||||
type: idea
|
||||
|
||||
---
|
||||
|
||||
**Is your idea related to a problem? Please describe.**
|
||||
|
||||
A clear and concise description of what the problem is. Eg:
|
||||
As a user, I would like [...]
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
TW5_BUILD_OUTPUT: "./output"
|
||||
TW5_BUILD_ARCHIVE: "./output"
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
|
||||
40
.github/workflows/eslint.yml
vendored
40
.github/workflows/eslint.yml
vendored
@@ -1,40 +0,0 @@
|
||||
name: ESLint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: lint-${{ github.event.pull_request.number || github.ref_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# Needed for GitHub Checks API
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --include=dev
|
||||
|
||||
- name: Run ESLint with reviewdog (GitHub Checks)
|
||||
uses: reviewdog/action-eslint@v1
|
||||
with:
|
||||
eslint_flags: '.'
|
||||
reporter: github-pr-check
|
||||
fail_level: error
|
||||
level: error
|
||||
tool_name: ESLint PR code
|
||||
55
.github/workflows/pr-check-build-size.yml
vendored
55
.github/workflows/pr-check-build-size.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: Calculate PR build size
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
paths:
|
||||
- 'boot/**'
|
||||
- 'core/**'
|
||||
- 'themes/tiddlywiki/snowwhite/**'
|
||||
- 'themes/tiddlywiki/vanilla/**'
|
||||
|
||||
jobs:
|
||||
calculate-build-size:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: read
|
||||
contents: read
|
||||
outputs:
|
||||
pr_size: ${{ steps.get_sizes.outputs.pr_size }}
|
||||
base_size: ${{ steps.get_sizes.outputs.base_size }}
|
||||
steps:
|
||||
- name: build-size-check
|
||||
id: get_sizes
|
||||
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: size:calc
|
||||
|
||||
dispatch-followup:
|
||||
needs: calculate-build-size
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: write # Required to dispatch another workflow
|
||||
pull-requests: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Trigger follow-up workflow
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'pr-comment-build-size.yml',
|
||||
ref: 'master',
|
||||
inputs: {
|
||||
pr_number: '${{ github.event.pull_request.number }}',
|
||||
base_ref: '${{ github.event.pull_request.base.ref }}',
|
||||
pr_size: '${{ needs.calculate-build-size.outputs.pr_size }}',
|
||||
base_size: '${{ needs.calculate-build-size.outputs.base_size }}'
|
||||
}
|
||||
});
|
||||
36
.github/workflows/pr-comment-build-size.yml
vendored
36
.github/workflows/pr-comment-build-size.yml
vendored
@@ -1,36 +0,0 @@
|
||||
name: Comment on PR build size (Trusted workflow)
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
required: true
|
||||
type: string
|
||||
base_ref:
|
||||
required: true
|
||||
type: string
|
||||
pr_size:
|
||||
required: true
|
||||
type: string
|
||||
base_size:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
comment-on-pr:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Build and check size
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ inputs.pr_number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ inputs.base_ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: size:comment
|
||||
pr_size: ${{ inputs.pr_size }}
|
||||
base_size: ${{ inputs.base_size }}
|
||||
37
.github/workflows/pr-validation.yml
vendored
37
.github/workflows/pr-validation.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: PR Validation
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
jobs:
|
||||
validate-pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Step 1: Validate PR paths
|
||||
- name: Validate PR Paths
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: rules
|
||||
continue-on-error: true
|
||||
|
||||
# Step 2: Validate change notes
|
||||
- name: Validate Change Notes
|
||||
uses: TiddlyWiki/cerebrus@v6
|
||||
with:
|
||||
pr_number: ${{ github.event.pull_request.number }}
|
||||
repo: ${{ github.repository }}
|
||||
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
mode: changenotes
|
||||
continue-on-error: false
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.4.0
|
||||
TW5_BUILD_VERSION=v5.3.7
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
@@ -73,8 +73,10 @@ rm $TW5_BUILD_OUTPUT/dev/static/*
|
||||
|
||||
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
|
||||
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
||||
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
|
||||
|
||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||
|
||||
@@ -103,7 +105,6 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
fi
|
||||
|
||||
# /index.html Main site
|
||||
# /external-(version).html External core version of main site
|
||||
# /favicon.ico Favicon for main site
|
||||
# /static.html Static rendering of default tiddlers
|
||||
# /alltiddlers.html Static rendering of all tiddlers
|
||||
@@ -116,7 +117,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--version \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build favicon static index external-js \
|
||||
--build favicon static index \
|
||||
|| exit 1
|
||||
|
||||
# /empty.html Empty
|
||||
@@ -154,14 +155,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tour \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js tour.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /surveys.html surveys edition
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tiddlywiki-surveys \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--build index \
|
||||
--rendertiddler $:/core/save/all tour.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /share.html Custom edition for sharing via the URL
|
||||
@@ -200,7 +194,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/xlsx-utils \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/xlsx-utils/ \
|
||||
--build external \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/resumebuilder/index.html Resume builder edition
|
||||
@@ -216,7 +210,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/text-slicer \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/text-slicer/ \
|
||||
--build external \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/translators/index.html Translators edition
|
||||
@@ -248,7 +242,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tw5.com-docs \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT/editions/tw5.com-docs/ \
|
||||
--build external \
|
||||
--build index \
|
||||
|| exit 1
|
||||
|
||||
# /editions/twitter-archivist/index.html Twitter Archivist edition
|
||||
@@ -271,7 +265,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/innerwikidemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/innerwiki/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/innerwiki/index.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/dynaview/index.html Demo wiki with DynaView plugin
|
||||
@@ -281,7 +275,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/dynaviewdemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/dynaview/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/dynaview/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/dynaview/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
@@ -295,17 +289,37 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/katexdemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/katex/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/katex/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
|
||||
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/tahoelafs \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
|
||||
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/d3demo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/codemirrordemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/codemirror/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/codemirror/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/codemirror/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
@@ -315,7 +329,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/markdowndemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/markdown/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/markdown/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/markdown/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
@@ -325,7 +339,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/classicparserdemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/tw2parser/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tw2parser/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tw2parser/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
@@ -335,7 +349,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/highlightdemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/highlight/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/highlight/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
@@ -345,7 +359,7 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/geospatialdemo \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all-external-js plugins/tiddlywiki/geospatial/index.html text/plain \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/geospatial/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/geospatial/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
|
||||
157
boot/boot.js
157
boot/boot.js
@@ -8,8 +8,6 @@ On the server this file is executed directly to boot TiddlyWiki. In the browser,
|
||||
|
||||
\*/
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
|
||||
var _boot = (function($tw) {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
@@ -46,8 +44,12 @@ $tw.utils.hop = function(object,property) {
|
||||
return object ? Object.prototype.hasOwnProperty.call(object,property) : false;
|
||||
};
|
||||
|
||||
/** @deprecated Use Array.isArray instead */
|
||||
$tw.utils.isArray = value => Array.isArray(value);
|
||||
/*
|
||||
Determine if a value is an array
|
||||
*/
|
||||
$tw.utils.isArray = function(value) {
|
||||
return Object.prototype.toString.call(value) == "[object Array]";
|
||||
};
|
||||
|
||||
/*
|
||||
Check if an array is equal by value and by reference.
|
||||
@@ -126,22 +128,35 @@ $tw.utils.pushTop = function(array,value) {
|
||||
return array;
|
||||
};
|
||||
|
||||
/** @deprecated Use instanceof Date instead */
|
||||
$tw.utils.isDate = value => value instanceof Date;
|
||||
/*
|
||||
Determine if a value is a date
|
||||
*/
|
||||
$tw.utils.isDate = function(value) {
|
||||
return Object.prototype.toString.call(value) === "[object Date]";
|
||||
};
|
||||
|
||||
/** @deprecated Use array iterative methods instead */
|
||||
/*
|
||||
Iterate through all the own properties of an object or array. Callback is invoked with (element,title,object)
|
||||
*/
|
||||
$tw.utils.each = function(object,callback) {
|
||||
var next,f,length;
|
||||
if(object) {
|
||||
if(Array.isArray(object)) {
|
||||
object.every((element,index,array) => {
|
||||
const next = callback(element,index,array);
|
||||
return next !== false;
|
||||
});
|
||||
if(Object.prototype.toString.call(object) == "[object Array]") {
|
||||
for(f=0, length=object.length; f<length; f++) {
|
||||
next = callback(object[f],f,object);
|
||||
if(next === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object.entries(object).every(entry => {
|
||||
const next = callback(entry[1], entry[0], object);
|
||||
return next !== false;
|
||||
});
|
||||
var keys = Object.keys(object);
|
||||
for(f=0, length=keys.length; f<length; f++) {
|
||||
var key = keys[f];
|
||||
next = callback(object[key],key,object);
|
||||
if(next === false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -316,13 +331,32 @@ $tw.utils.htmlDecode = function(s) {
|
||||
return s.toString().replace(/</mg,"<").replace(/ /mg,"\xA0").replace(/>/mg,">").replace(/"/mg,"\"").replace(/&/mg,"&");
|
||||
};
|
||||
|
||||
/** @deprecated Use window.location.hash instead. */
|
||||
$tw.utils.getLocationHash = () => window.location.hash;
|
||||
/*
|
||||
Get the browser location.hash. We don't use location.hash because of the way that Firefox auto-urldecodes it (see http://stackoverflow.com/questions/1703552/encoding-of-window-location-hash)
|
||||
*/
|
||||
$tw.utils.getLocationHash = function() {
|
||||
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 */
|
||||
$tw.utils.pad = function(value,length = 2) {
|
||||
const s = value.toString();
|
||||
return s.padStart(length, "0");
|
||||
/*
|
||||
Pad a string to a given length with "0"s. Length defaults to 2
|
||||
*/
|
||||
$tw.utils.pad = function(value,length) {
|
||||
length = length || 2;
|
||||
var s = value.toString();
|
||||
if(s.length < length) {
|
||||
s = "000000000000000000000000000".substr(0,length - s.length) + s;
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
// Convert a date into UTC YYYYMMDDHHMMSSmmm format
|
||||
@@ -596,7 +630,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||
// Compile the code into a function
|
||||
var fn;
|
||||
if($tw.browser) {
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename); // eslint-disable-line no-eval -- See https://github.com/TiddlyWiki/TiddlyWiki5/issues/6839
|
||||
fn = window["eval"](code + "\n\n//# sourceURL=" + filename);
|
||||
} else {
|
||||
if(sandbox){
|
||||
fn = vm.runInContext(code,sandbox,filename)
|
||||
@@ -607,7 +641,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||
// Call the function and return the exports
|
||||
return fn.apply(null,contextValues);
|
||||
};
|
||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||
/*
|
||||
Run code in a sandbox with only the specified context variables in scope
|
||||
*/
|
||||
@@ -765,13 +799,12 @@ the password, and to encrypt/decrypt a block of text
|
||||
$tw.utils.Crypto = function() {
|
||||
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
||||
currentPassword = null,
|
||||
callSjcl = function(method,inputText,password,options) {
|
||||
options = options || {};
|
||||
callSjcl = function(method,inputText,password) {
|
||||
password = password || currentPassword;
|
||||
var outputText;
|
||||
try {
|
||||
if(password) {
|
||||
outputText = sjcl[method](password,inputText,options);
|
||||
outputText = sjcl[method](password,inputText);
|
||||
}
|
||||
} catch(ex) {
|
||||
console.log("Crypto error:" + ex);
|
||||
@@ -797,8 +830,7 @@ $tw.utils.Crypto = function() {
|
||||
return !!currentPassword;
|
||||
}
|
||||
this.encrypt = function(text,password) {
|
||||
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
|
||||
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
|
||||
return callSjcl("encrypt",text,password);
|
||||
};
|
||||
this.decrypt = function(text,password) {
|
||||
return callSjcl("decrypt",text,password);
|
||||
@@ -1401,7 +1433,7 @@ $tw.Wiki = function(options) {
|
||||
checkTiddler = function(tiddler,title) {
|
||||
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);
|
||||
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
||||
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
||||
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
||||
pluginTiddlers.push(tiddler);
|
||||
registeredTitles.push(tiddler.fields.title);
|
||||
@@ -1498,8 +1530,7 @@ Define all modules stored in ordinary tiddlers
|
||||
*/
|
||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||
this.each(function(tiddler,title) {
|
||||
// Modules in draft tiddlers are disabled
|
||||
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
|
||||
if(tiddler.hasField("module-type")) {
|
||||
switch(tiddler.fields.type) {
|
||||
case "application/javascript":
|
||||
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||
@@ -1526,11 +1557,6 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
||||
this.eachShadow(function(tiddler,title) {
|
||||
// Don't define the module if it is overidden by an ordinary tiddler
|
||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||
if(tiddler.hasField("draft.of")) {
|
||||
// Report a fundamental problem
|
||||
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
|
||||
return;
|
||||
}
|
||||
// Define the module
|
||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||
}
|
||||
@@ -1879,7 +1905,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
||||
fileSize = fs.statSync(filepath).size,
|
||||
data;
|
||||
if(fileSize > $tw.config.maxEditFileSize) {
|
||||
data = "File " + filepath + " not loaded because it is too large";
|
||||
data = "File " + filepath + "not loaded because it is too large";
|
||||
console.log("Warning: " + data);
|
||||
ext = ".txt";
|
||||
} else {
|
||||
@@ -1950,41 +1976,22 @@ filepath: pathname of the directory containing the specification file
|
||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var tiddlers = [];
|
||||
// Read the specification
|
||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"), function(e) {
|
||||
console.log("Warning: tiddlywiki.files in " + filepath + " invalid: " + e.message);
|
||||
return {};
|
||||
});
|
||||
|
||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
||||
// Helper to process a file
|
||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||
pathname = path.resolve(filepath,filename),
|
||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||
fileTooLarge = false,
|
||||
text, fileTiddlers;
|
||||
|
||||
if("_canonical_uri" in fields) {
|
||||
text = "";
|
||||
} else if(fs.statSync(pathname).size > $tw.config.maxEditFileSize) {
|
||||
var msg = "File " + pathname + " not loaded because it is too large";
|
||||
console.log("Warning: " + msg);
|
||||
fileTooLarge = true;
|
||||
text = isTiddlerFile ? msg : "";
|
||||
} else {
|
||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8");
|
||||
}
|
||||
|
||||
fileTiddlers;
|
||||
if(isTiddlerFile) {
|
||||
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
|
||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
||||
} else {
|
||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||
}
|
||||
var combinedFields = $tw.utils.extend({},fields,metadata);
|
||||
if(fileTooLarge && isTiddlerFile) {
|
||||
delete combinedFields.type; // type altered
|
||||
}
|
||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||
@@ -1993,7 +2000,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var value = tiddler[name];
|
||||
switch(fieldInfo.source) {
|
||||
case "subdirectories":
|
||||
value = $tw.utils.stringifyList(path.relative(rootPath, filename).split(path.sep).slice(0, -1));
|
||||
value = path.relative(rootPath, filename).split(path.sep).slice(0, -1);
|
||||
break;
|
||||
case "filepath":
|
||||
value = path.relative(rootPath, filename).split(path.sep).join('/');
|
||||
@@ -2014,10 +2021,10 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
value = path.extname(filename);
|
||||
break;
|
||||
case "created":
|
||||
value = $tw.utils.stringifyDate(new Date(fs.statSync(pathname).birthtime));
|
||||
value = new Date(fs.statSync(pathname).birthtime);
|
||||
break;
|
||||
case "modified":
|
||||
value = $tw.utils.stringifyDate(new Date(fs.statSync(pathname).mtime));
|
||||
value = new Date(fs.statSync(pathname).mtime);
|
||||
break;
|
||||
}
|
||||
if(fieldInfo.prefix) {
|
||||
@@ -2059,7 +2066,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
} else if(tidInfo.suffix) {
|
||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||
}
|
||||
tidInfo.fields = tidInfo.fields || {};
|
||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||
});
|
||||
// Process any listed directories
|
||||
@@ -2081,7 +2087,6 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||
var thisPath = path.relative(filepath, files[t]),
|
||||
filename = path.basename(thisPath);
|
||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||
dirSpec.fields = dirSpec.fields || {};
|
||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||
}
|
||||
}
|
||||
@@ -2345,7 +2350,6 @@ $tw.loadTiddlersNode = function() {
|
||||
});
|
||||
// Load the core tiddlers
|
||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
|
||||
// Load any extra plugins
|
||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||
@@ -2419,7 +2423,6 @@ $tw.boot.initStartup = function(options) {
|
||||
// System paths and filenames
|
||||
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
||||
$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($tw.boot.argv.length === 0) {
|
||||
$tw.boot.argv = ["--help"];
|
||||
@@ -2544,10 +2547,10 @@ $tw.boot.execStartup = function(options){
|
||||
if($tw.safeMode) {
|
||||
$tw.wiki.processSafeMode();
|
||||
}
|
||||
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
|
||||
// Tiddlers should appear last so that they may overwrite shadows during module registration
|
||||
$tw.wiki.defineShadowModules();
|
||||
// Register typed modules from the tiddlers we've just loaded
|
||||
$tw.wiki.defineTiddlerModules();
|
||||
// And any modules within plugins
|
||||
$tw.wiki.defineShadowModules();
|
||||
// Make sure the crypto state tiddler is up to date
|
||||
if($tw.crypto) {
|
||||
$tw.crypto.updateCryptoStateTiddler();
|
||||
@@ -2616,13 +2619,11 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
||||
$tw.boot.log(s.join(" "));
|
||||
// Execute task
|
||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||
const thenable = task.startup();
|
||||
if(thenable && typeof thenable.then === "function"){
|
||||
thenable.then(asyncTaskCallback);
|
||||
return true;
|
||||
} else {
|
||||
return asyncTaskCallback();
|
||||
task.startup();
|
||||
if(task.name) {
|
||||
$tw.boot.executedStartupModules[task.name] = true;
|
||||
}
|
||||
return $tw.boot.executeNextStartupTask(callback);
|
||||
} else {
|
||||
task.startup(asyncTaskCallback);
|
||||
return true;
|
||||
@@ -2767,8 +2768,6 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) !== "undefined") {
|
||||
exports.TiddlyWiki = _boot;
|
||||
} else {
|
||||
|
||||
@@ -12,8 +12,6 @@ See Boot.js for further details of the boot process.
|
||||
|
||||
\*/
|
||||
|
||||
/* eslint-disable @stylistic/indent */
|
||||
|
||||
var _bootprefix = (function($tw) {
|
||||
|
||||
"use strict";
|
||||
@@ -116,8 +114,6 @@ return $tw;
|
||||
|
||||
});
|
||||
|
||||
/* eslint-enable @stylistic/indent */
|
||||
|
||||
if(typeof(exports) === "undefined") {
|
||||
// Set up $tw global for the browser
|
||||
window.$tw = _bootprefix(window.$tw);
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
title: Community Cards Caveats
|
||||
created: 20250909171928024
|
||||
modified: 20250909171928024
|
||||
|
||||
''Please note that [[Community Cards]] are a new initiative started in September 2025. There is further work required to complete the team and people information.''
|
||||
@@ -1,11 +0,0 @@
|
||||
title: Community Cards
|
||||
tags: Community
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
|
||||
The purpose of Community Cards is to allow project plans and other community activities to be linked to the people who are involved in them. They also allow people to share their interests and activities in the TiddlyWiki community, and to help people in the TiddlyWiki community get to know each other better.
|
||||
|
||||
{{Community Cards Caveats}}
|
||||
|
||||
* [[Submitting a Community Card]]
|
||||
* [[Displaying Community Cards]]
|
||||
@@ -1,26 +0,0 @@
|
||||
title: Displaying Community Cards
|
||||
tags: [[Community Cards]]
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
|
||||
!! Cards for people
|
||||
|
||||
This is an inline card for <<community-card-pill-person title:"@Jermolene">> and <<community-card-pill-person title:"@ericshulman">> which can be used in the middle of a sentence.
|
||||
|
||||
This is a stack of inline cards:
|
||||
|
||||
<<community-card-pill-stack-person>>
|
||||
|
||||
Here is a full format card:
|
||||
|
||||
<<community-card-person title:"@Jermolene">>
|
||||
|
||||
This is how the card looks when there is no such person:
|
||||
|
||||
<<community-card-person title:"@MissingPerson">>
|
||||
|
||||
!! Cards for teams
|
||||
|
||||
This is a card for a project team:
|
||||
|
||||
<<community-card-team title:"Project Team">>
|
||||
@@ -1,36 +0,0 @@
|
||||
title: Submitting a Community Card
|
||||
tags: [[Community Cards]]
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
|
||||
Anyone associated with the TiddlyWiki community can submit a Community Card. The submission process currently involves making a GitHub pull request but we intend to provide a more user-friendly submission process in the future.
|
||||
|
||||
Pull requests to add or update a community card should be made against the `tiddlywiki-com` branch of the [[TiddlyWiki repository|https://github.com/TiddlyWiki/TiddlyWiki5]] in the directory `community/people`.
|
||||
|
||||
The card should be a TiddlyWiki tiddler with the following fields:
|
||||
|
||||
|!Field |!Required|!Description |
|
||||
|`title`|Yes |The username of the person represented by the card, starting with `@` (e.g. `@Jermolene`). This is the title of the card and should be unique |
|
||||
|`tags`|Yes |The tags for the card, including `Community/Person` |
|
||||
|`fullname`|Yes |The full name of the person or group represented by the card |
|
||||
|`avatar`|Yes |The base64 representation of the 32x32 avatar image for the person represented by the card |
|
||||
|`first-sighting`|No |The date of the first sighting in the community of the person represented by the card. This should be in ISO 8601 format (YYYY-MM-DD) |
|
||||
|`talk.tiddlywiki.org`|Yes |The username of the person or group on the TiddlyWiki Talk forum |
|
||||
|`github`|No |The username of the person or group on GitHub |
|
||||
|`linkedin`|No |The URL of the LinkedIn profile for the person or group represented by the card |
|
||||
|`flickr`|No |The URL of the Flickr profile for the person or group represented by the card |
|
||||
|`homepage`|No |The URL of the homepage for the person or group represented by the card |
|
||||
|`email`|No |The email address of the person or group represented by the card |
|
||||
|`text`|Yes |The text of the card. This should include a brief description of the person or group represented by the card, and any other relevant information |
|
||||
|
||||
! Rules for Community Cards
|
||||
|
||||
Community cards must observe the following rules. It is intended to enforce them with an automated script, but for the moment they will be manually checked.
|
||||
|
||||
* `title` must be unique and start with `@`
|
||||
* `tags` must include `Community/Person`
|
||||
* `fullname` must be provided
|
||||
* `avatar` must be a base64 representation of a 32x32 image, with a limit of 1KB. [[Squoosh|https://squoosh.app/]] is recommended for resizing and compressing images
|
||||
* `first-sighting` should be in ISO 8601 format (YYYY-MM-DD)
|
||||
* `talk.tiddlywiki.org` must be provided
|
||||
* `text` total size must not exceed 2KB
|
||||
@@ -1,10 +0,0 @@
|
||||
title: @Arlen22
|
||||
tags: Community/Person
|
||||
fullname: Arlen Beiler
|
||||
first-sighting: 2011-06-20
|
||||
talk.tiddlywiki.org: arlen22
|
||||
github: Arlen22
|
||||
homepage: arlen22.github.io
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wEEEAAVABUAFQAVABYAFQAYABoAGgAYACEAIwAfACMAIQAwAC0AKQApAC0AMABJADQAOAA0ADgANABJAG8ARQBRAEUARQBRAEUAbwBiAHcAYQBaAGEAdwBiALEAiwB7AHsAiwCxAMwArACiAKwAzAD4AN0A3QD4ATgBKAE4AZcBlwIkEQAVABUAFQAVABYAFQAYABoAGgAYACEAIwAfACMAIQAwAC0AKQApAC0AMABJADQAOAA0ADgANABJAG8ARQBRAEUARQBRAEUAbwBiAHcAYQBaAGEAdwBiALEAiwB7AHsAiwCxAMwArACiAKwAzAD4AN0A3QD4ATgBKAE4AZcBlwIk/8IAEQgAQABAAwEiAAIRAQMRAf/EADAAAAIDAQEAAAAAAAAAAAAAAAMFAQQGAgABAQEBAQEAAAAAAAAAAAAAAAIDAQAE/9oADAMBAAIQAxAAAADIRMd3XctQlXtCTTmB6RFvANDouy4DYwEEar6YVM7ocz57mcqnZys+V2azZU4XZSoiZqhQt9TKOlnO+GOl1HyoUPXLn//EACYQAAICAQQCAgEFAAAAAAAAAAECABEDBBIhMUFRECITFCMycZH/2gAIAQEAAT8AI4Bv4ryAeBAnANHuNidWogEwYHNRsdfA8iruVMOIu6iYtK4c714vgTDpXyOfrQHdifoArEXxM2mR0NeOhUzI+LJzYbuHszCm5hYseZh0gXYWFIai4cWJgFJuFKYvtr2sJRuB9fUzgDHlGMHia2757uYsYc0TNHpsSmzzMONjl9iu74iK6PbWT7gv/RMiZDk+qcA3NXkAVl3gE+ADU1PDVdiaDCGJZjQEyowKANS1ZMwK+HJ+3a0KUDqYnYINxJ3eItDk81M2cZD+NVIrmanU/wAl2gCZiGNiaFziJ3LYIHcXMrLvDABe17EN1vCgqR2TNPnGTBSBbDTeV3c2amdlxPuD2C3H9epqmV628xqsUYmdiuwkVVTSZ0Q/dxwYdScrgBRsqONi2KQX7mo1G4WCK20B6j6p/VpcfMXPVQ9mbhx9eLgZrFGDUZB1DqMrCma4xN8mDcR5qK5Rgw7Hx//EABwRAQEBAQACAwAAAAAAAAAAAAECABEDIhIxQf/aAAgBAgEBPwDVQYpfzd66qDeOSn7yEmH23ffDAi66mug6DM9N8HTAY3//xAAcEQEBAQEAAgMAAAAAAAAAAAABAAIREBIiQVH/2gAIAQMBAT8AglC+rJbdCT1vVC33l83tj2OPLS+AJ3+Tf//Z
|
||||
|
||||
I make random software.
|
||||
@@ -1,14 +0,0 @@
|
||||
title: @Christian_Byron
|
||||
tags: Community/Person
|
||||
fullname: Christian Byron
|
||||
talk.tiddlywiki.org: Christian_Byron
|
||||
github: ceebeetree
|
||||
linkedin: www.linkedin.com/in/christian-byron-b84a594/
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEBAAMBAAAAAAAAAAAAAAAHBgEDBQQBAAMBAAAAAAAAAAAAAAAAAAABAwX/2gAMAwEAAhADEAAAADv2xtJlY03sqePW3ARS1RSydIhcH//EACcQAAICAgIBAgYDAAAAAAAAAAECAwQFEQASMRMhBhBBk8HRIzJx/9oACAEBAAE/AMFQxs+NExqJLMCwYE+SOT4bF3qr+hAIpRsDQ6lWH0Yco4S/eVniRVQHXZzrZ5dwGQpQtNII2RfJVvHMRl5cbKxC94n/ALp+RxfiKpNcgMMUqPIwjcnWip/I5XtUowaL3Ujir/xt79Glb6/4OZ7MV5oEpUzuIa7MPB14A5jpoYLsEsydo1bbLre+CWEEEYab7Uf74ZYSSThpvtR/vmRmhnuzywp1jZtquta+VPM49qlcy24lf017At7g8uZnHrUsGK3Ez+m3UBvcnXy//8QAHhEAAgEFAAMAAAAAAAAAAAAAAQIDAAQRIkEyUaH/2gAIAQIBAT8AmiuVlZkLEeQOflJPcvMAF0z65V+h0YIW52rBDuxUrztf/8QAIxEBAAEDAwMFAAAAAAAAAAAAAgEAAxEEBSMSQcEiMVJxof/aAAgBAwEBPwC/Z1ZvNBOYz1Gc/lDUat3ySPRM/H2P3W4hcbIldpxnxW3BcjQk9oznzX//2Q==
|
||||
|
||||
Hello ~TiddlyWikiers - I have been a long time fan, recent contributor to the TW community.
|
||||
Recently I have volunteered to run the [[TiddlyWiki Newsletter|https://tiddlywiki.substack.com/]] to spread the great news about TW.
|
||||
|
||||
I have been in the IT industry for about thirty years, mostly as a consultant and technical arcitect.
|
||||
More recently I went back to study a masters in IT focussing on AI and data science.
|
||||
Now my partner and I have started our own business ([[Sphere Innovations|https://sphere-innovations.com.au]]) - in consulting and building web applications for small to medium size businesses here in Australia.
|
||||
@@ -1,29 +0,0 @@
|
||||
title: @ericshulman
|
||||
tags: Community/Person Community/Team/Contributors
|
||||
fullname: Eric Shulman
|
||||
first-sighting: 2005-06-21
|
||||
talk.tiddlywiki.org: ericshulman
|
||||
github: ericshulman
|
||||
homepage: tiddlytools.com
|
||||
email: elsdesign@gmail.com
|
||||
avatar: iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAD/ElEQVR42o2Tf2iUdRzH37e7rOa222233bab3mqKU9QihCAi+isKwX/sh5UQhGYQhNAvQowRUoghQWDOIJtQmOY0M92ZmVGm0WbTyZI1Nnft99S1jc3dPT9efffg/bHdLn19Hp4HPjzv9/fz+fL5aE58PwUkjzzFVC4P/G/k6E445Pc+uceeaqnv7Ogd6Rq68PPhrc+vkiERWOLT/+Ib8uQHNiXax3BIM0mC+CEtl2G7X9mIeCV+9Ejrr2MAtgkH14SNBRZXrYYPNF86nsXCkx/8dATAsp0JhknQTYJrTHg5SNI0qMekb+aw8Hr74WCKpNNu/0Kck5ymkRMcZz/1Jv5g2CUFbZYelrbMvlBMonHvJK3JuPsdTQxwExc8XG7SxF7OcxGScP6wRGCG/Asjf39VPydTzbQyRBrXBKToBCP/nQQ9VpIDO6SumU3EjUFLzX766HMG0mIvoJnXEbU47GGXc4TGBs3zWp5Jh7F47omdf56hy9lLIz3gyYfZSQMJztFEH3KEDg+bf1dkzkO9Savks7H9NLqnuEw3MEU314nTwABj/MV2R6y8JL+0wKdM8MtX23aFy04dF5mg08QI6XYsemmzRfiMDP5Mg1emK4ienZxi0p0gBfRwhSHAxgXGGeS6tYUdu6TPA3Ofr3Mfj9Bv4zHMDaCTMcBlnG4cJqx64sagN9Ngw3RJoa5R+MftI8k1Wm7NcSsH6KKPFGBbG1n1srQ+06DWpJ59cRhsGKGbo0wBFpDgNGcBcHGsl9BuSZmjfCRHWnv0BtgOcJVWwAZG2cw+3uErAKacZ6hq32PkGWuNSaxsHgIHxqjje5I4/Ms2dCt+BHpcUT4ai0j5sw22TCea2sCBbz3BOjaRFj+JeAE46IoHxlUmlfrmWuZT+8Ae935fjljDe3zpLdEJxGriLHdFtL8mKC2cbbAgIOXVBemwBhHibZq4xN/0YgPrESsRsiMs+C1zEwwFxqBqs4hY2yhlKeIUab5GLEM8SLlVRslu77jZhEwL/ofKKZ4uknxiiLO0cYFGFpJPMTGiRO0iQqtNrX7NxueTcahqv4/FTpgwFYinOcoxtiLKWEwF+U6Mqv5FuVlWSQHzvBWmKmUqIEg1YiMfIu6lhjKCRK0YkXelwoDmIjztWrCot5KQs5R5zKccIVZQwl3cTaVdQVGnfOkrzFbDuvuJWTVuBcXcQ5iFlFFAmBynlBKKH/f6z06pX6r6pJoSQlaeW2gsighi3na1E6HwNSkUUHbS45FXG7ajhIi68+1cO98qtqqJEHzTW6LbEfUstER1ef2llBKhiGqKW7VGUk6lT7dnmS/gnZMf1KPaoI16VWsrA1KhX3dObo5m9VqQpff/AFTcI4hMzFV+AAAAAElFTkSuQmCC
|
||||
|
||||
\define wiki(text,topic) [[$text$|https://en.wikipedia.org/wiki/$topic$]]
|
||||
|
||||
''Hello! My name is Eric Shulman''. I am the author of ''[[www.TiddlyTools.com|http://www.TiddlyTools.com]] (Small Tools for Big Ideas! ™)'', a popular collection of original plugins, macros, widgets, templates and stylesheets for TiddlyWiki that I have created and shared with the TiddlyWiki community.
|
||||
|
||||
<<<
|
||||
Think of TiddlyTools as a ''virtual hardware store and "demonstration showroom"'', offering tools, parts and techniques that provide a rich variety of new functionality and feature enhancements to help you ''turn a general-purpose TiddlyWiki "info-house" into a comfortable, custom-built "info-home"''.
|
||||
|
||||
The TiddlyWiki core system provides the basic structure and utilities: the foundation, framing, walls, roof, windows/doors, plumbing, heating, and electrical systems. Then, TiddlyTools helps you with all the "finish work": the appliances, fixtures, lighting, cabinets, furniture, paint, wallpaper, carpeting, etc. ''to best suit your specific needs and personal style''.
|
||||
<<<
|
||||
|
||||
Since the early days of TiddlyWiki (April 2005), I have worked closely with its inventor, [[Jeremy Ruston|https://jermolene.com/]], to help develop and improve TiddlyWiki's core functions. I am also a key contributor and administrator of the online TiddlyWiki [[Discourse|https://talk.TiddlyWiki.org]] and [[GoogleGroups|https://groups.google.com/forum/#!forum/tiddlywiki]] discussion forums, providing ongoing assistance to the worldwide TiddlyWiki community. I have written over 15,000 detailed responses to individual questions posted online. For several years I was also the lead developer and maintainer of the [[TiddlyWiki Classic|https://classic.tiddlywiki.com/]] codebase.
|
||||
|
||||
I was born and raised in suburban Long Island, NY, and attended [[Carnegie Mellon University (CMU)|https://www.cmu.edu/]] in Pittsburgh, PA, where I studied ''Computer Science, Cognitive Psychology, Sociology, Human Factors Design, and Artificial Intelligence''. As an undergraduate at CMU, I was privileged to work with some of the major luminaries in early software research and design, including <<wiki "Herbert Simon" "Herbert_A._Simon">>, <<wiki "Allen Newell" "Allen_Newell">>, <<wiki "James Gosling" "James_Gosling">>, and <<wiki "Raj Reddy" "Raj_Reddy">>. I was also employed in several Computer Science Department research projects, including the development of speech recognition technologies, graphical interface systems, and interactive applications for instruction in physics, art and music. I received a ''Bachelor of Science in "Interactive Systems Design"'' from CMU in 1985.
|
||||
|
||||
During my early post-graduate years, I worked for several notable software development companies, including
|
||||
<<wiki "Honeywell Information Systems" "Honeywell#Honeywell_Information_Systems">> and <<wiki "Lotus Software" "Lotus_Software">>. I was an integral member of the <<wiki "1-2-3 spreadsheet"
|
||||
"Lotus_1-2-3">> development team where I helped create the first GUI-based application interfaces for Microsoft Windows and IBM OS/2.
|
||||
|
||||
Since 1998, I have been an ''independent design consultant'', living and working in Silicon Valley, where I apply more than 40 years of experience to provide ''analysis, design and software development services'' for commercial companies and not-for-profit organizations, with emphasis on ''information architecture'' and ''interaction/visual design standards'' to improve ease-of-use for new and existing software products and online environments.
|
||||
@@ -1,21 +0,0 @@
|
||||
title: @Jermolene
|
||||
tags: Community/Person
|
||||
fullname: Jeremy Ruston
|
||||
first-sighting: 2004-09-20
|
||||
talk.tiddlywiki.org: jeremyruston
|
||||
github: Jermolene
|
||||
linkedin: www.linkedin.com/in/jermy
|
||||
flickr: www.flickr.com/photos/jermy/
|
||||
bluesky: https://bsky.app/profile/jermolene.bsky.social
|
||||
homepage: jermolene.com
|
||||
email: jeremy@jermolene.com
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAtAAEBAAMAAAAAAAAAAAAAAAAHBgIEBQEBAQEBAAAAAAAAAAAAAAAAAgQBBf/aAAwDAQACEAMQAAAANF4uTuPRhD2nBLnUiJvKM0DtMKy//8QAKxAAAgIBAwMDAQkAAAAAAAAAAQIDBBEABRITITEiMkFxFEJRUmFicoGR/9oACAEBAAE/AInTA6gUGP4ZOQbW1bPsmyUq1q+gmvFPUzZPDkPamtwqU75ks04JakroVcg5RwRjg66NUx25KbzqJYyMngfqSuq0M3NZYIebJIvZozIvI/iNPcp/aalSdJXsS4VcKeIzlvU3jVTcYLNiaGISrjkhWQYDfQ63pYAzCDBsOiu7Dsx4EHH6r2w2ttimjd2IsNErhhJHKI04/uzqxuCxpBYVVWKSHqwMyMSQ33SB7dUJFmlkMYRgnqZgCMf7rf8AeEt3A9YOhjXAb2k8u7dtT1RZeOtXmYxiOPj4ZWY/lb51skqUNnNW/wBNzC7IpB6gQeeB/jq/fqGOaLbowuYn5MAQOw8LjW5Vmeo0qIsqYLLKjHIZmwv9fB1//8QAHxEAAQMEAwEAAAAAAAAAAAAAEQABAgMSIWExMkFR/9oACAECAQE/AD9iTy2lJmHUB8BVKM4SNSOj46a29saX/8QAHREAAgICAwEAAAAAAAAAAAAAAQIAAwQRITGBkf/aAAgBAwEBPwDHpFpJZtamVSiBWT2Yt7hmCDsb+TKtsKqpGg3M/9k=
|
||||
|
||||
I'm the original inventor of TiddlyWiki. You can hire me through my consultancy company [[Intertwingled Innovations|https://intertwingledinnovations.com]] or contact me directly.
|
||||
|
||||
Further information:
|
||||
|
||||
* A recording of the [[keynote I gave at QCon London in April 2024|https://www.infoq.com/presentations/bbc-micro/]], and the [[discussion on talk.tiddlywiki.org|https://talk.tiddlywiki.org/t/recording-of-jeremys-keynote-at-qcon-london-april-2024/10505]]. The talk mixes some nostalgia about my teenage activities with the BBC Micro with thoughts on the development of the software industry and insights gained from working with TiddlyWiki
|
||||
* An [[interview with me in The Inquirer|https://web.archive.org/web/20111103225832/http://www.theinquirer.net/inquirer/feature/2105529/bt-software-engineer-tells-telco-source]] by Wendy Grossman
|
||||
* A [[hilarious interview with me|https://www.youtube.com/watch?v=auyIhw8MTmQ]] from British television in 1983
|
||||
* Here's a video of a presentation I did in 2007 called [["How to Start an Open Source Project"|http://vimeo.com/856110]].
|
||||
@@ -1,19 +0,0 @@
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
|
||||
created: 20251110102157310
|
||||
first-sighting: 2019-03-01
|
||||
fullname: Lin Onetwo
|
||||
github: linonetwo
|
||||
homepage: https://wiki.onetwo.website/
|
||||
modified: 20251111184556193
|
||||
tags: Community/Person Community/Team/Contributors
|
||||
talk.tiddlywiki.org: linonetwo
|
||||
title: @linonetwo
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I don’t want to forget any of them. When I’m deeply focused on a task, it’s easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
|
||||
|
||||
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
|
||||
|
||||
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, I’ve enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
|
||||
|
||||
Most of my notes are open by default and shared publicly on my homepage as a digital garden.
|
||||
@@ -1,11 +0,0 @@
|
||||
title: @MotovunJack
|
||||
tags: Community/Person Community/Robot
|
||||
fullname: Motovun Jack
|
||||
first-sighting: 2012-01-12
|
||||
github: MotovunJack
|
||||
homepage: tiddlywiki.com
|
||||
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wEEEAAYABgAGAAYABkAGAAaAB0AHQAaACUAKAAjACgAJQA2ADIALgAuADIANgBSADsAPwA7AD8AOwBSAH0ATgBbAE4ATgBbAE4AfQBuAIYAbQBlAG0AhgBuAMYAnACKAIoAnADGAOUAwQC2AMEA5QEWAPgA+AEWAV4BTAFeAckByQJmEQAYABgAGAAYABkAGAAaAB0AHQAaACUAKAAjACgAJQA2ADIALgAuADIANgBSADsAPwA7AD8AOwBSAH0ATgBbAE4ATgBbAE4AfQBuAIYAbQBlAG0AhgBuAMYAnACKAIoAnADGAOUAwQC2AMEA5QEWAPgA+AEWAV4BTAFeAckByQJm/8IAEQgAQABAAwEiAAIRAQMRAf/EADAAAAIDAQEAAAAAAAAAAAAAAAMEAQIFBgABAQEBAQEAAAAAAAAAAAAAAAIDAQAE/9oADAMBAAIQAxAAAADZCfn5vZJz+rnODGtpbpm6O8xzG9lCiszXtikQhtkTBputBxURJuVVYlEdBaQ284mPDj6GmkNUblMxRmi7dKw//8QAKxAAAgIBAgUCBgMBAAAAAAAAAQIAAxESIQQTIkFRFGEjMUJxgaEyNGLR/9oACAEBAAE/AMmX3ilMkjPaV3ragZDtNRmoxpvA2sEqQcHEwJxlwa98nYbCU8TymDfSTvPVKMbZHkQcTU4yDH46tTiE8RxjLXnQp7Dx5MACgKuyqMAS1xXU7kjYTiEbWp3y0IucYbGx6e05hDAqMH/k59o3DfxAE5hss1MNzODdVraxu50ieppH1Tivi8O6eYQ1j4B6guAftChDMNjBqycHcCYJqdj2s3idRBHfpi/1Kie7PDo95w/EMxYM22n9yy5AzBc/iLe7dIqx7kyy2ypyOWoYTofhCyDAZtx4MOmpK9sncyx1NdSq2kBBt3EKf6mgIzDUPIiByuqk7faMLbOyEjuuxEAyo56AgeTA3KL1AYRm1CcvmkgAs2wHjEvPxGIMJPmHUQCQNothr32A0ggeYluplcAK2PlLbTytZUkdwI7V3lAQMgbAfP8AMoCV1AKMOR+pdsc5yD595mMmNIGD4h0vsfupHyBlTKW9znMd+TQnljPWqHYIqhwD1zKsqtjBzCAVAyBicnqG6jbOe0//xAAbEQEBAAMBAQEAAAAAAAAAAAABAAIRIRASQf/aAAgBAgEBPwBYbZDuXvnLE5OrkWJzxI4g33ift//EABsRAAMBAQADAAAAAAAAAAAAAAABEQIhEBJB/9oACAEDAQE/AMqjzHwjGoZXPHTb6Zp1/TRp1khYjW01xHqz/9k=
|
||||
|
||||
Motovun Jack is a robot that helps maintain the TiddlyWiki project infrastructure. It is not a person, but rather a set of automated scripts and tools that assist in managing the various services and resources used by the TiddlyWiki community.
|
||||
|
||||
The origin of the name "Motovun Jack" is a lovable and playful kitten encountered by [[@Jermolene]] in the beautiful medieval hill town of Motovun in Croatia. Jack was [[first adopted|https://github.com/TiddlyWiki/TiddlyWiki5/commit/ecfbaaa5641f14e1766ef17ef6416bf9aa992863]] as the TiddlyWiki 5 mascot in 2012.
|
||||
@@ -1,25 +0,0 @@
|
||||
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
|
||||
created: 20251110102157310
|
||||
first-sighting: 2009-11-14
|
||||
fullname: Mario Pietsch
|
||||
github: pmario
|
||||
homepage: https://wikilabs.github.io/
|
||||
modified: 20251110124935183
|
||||
tags: Community/Person Community/Team/Contributors
|
||||
talk.tiddlywiki.org: pmario
|
||||
title: @pmario
|
||||
type: text/vnd.tiddlywiki
|
||||
youtube: https://www.youtube.com/@pmario
|
||||
|
||||
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
|
||||
|
||||
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
|
||||
|
||||
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
|
||||
|
||||
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what that’s good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
|
||||
|
||||
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
|
||||
|
||||
Have fun!<br>
|
||||
Mario
|
||||
@@ -1,10 +0,0 @@
|
||||
title: TiddlyWiki People
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
tags: Community About
|
||||
|
||||
Members of the TiddlyWiki community who are involved in the development of TiddlyWiki and the running of the project are invited to [[create a Community Card|Submitting a Community Card]] so that they can be included in project plans and organisation charts. Community Cards can also showcase their interests and activities in the TiddlyWiki community.
|
||||
|
||||
{{Community Cards Caveats}}
|
||||
|
||||
<<community-card-pill-stack-person personFilter:"[tag[Community/Person]sort[title]]">>
|
||||
@@ -1,10 +0,0 @@
|
||||
title: TiddlyWiki Project
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
tags: Community About
|
||||
|
||||
The TiddlyWiki Project is the coordinated, ongoing effort to maintain and improve TiddlyWiki, and to support the TiddlyWiki community.
|
||||
|
||||
{{Community Cards Caveats}}
|
||||
|
||||
<$list filter="[tag[Community/Team]]" template="$:/tiddlywiki/community/cards/ViewTemplateBodyTemplateTeam"/>
|
||||
@@ -1,4 +0,0 @@
|
||||
title: Vacant Positions
|
||||
tags: [[TiddlyWiki Project]]
|
||||
|
||||
If you are interested in volunteering to help the project please get in touch with <<community-card-pill-person title:"@Jermolene">>.
|
||||
@@ -1,8 +0,0 @@
|
||||
title: Core Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
leader: @Jermolene
|
||||
team: @saqimtiaz
|
||||
|
||||
The core team is responsible for the maintenance and development of the TiddlyWiki core and official plugins.
|
||||
@@ -1,19 +0,0 @@
|
||||
title: Developer Experience Team
|
||||
tags: Community/Team
|
||||
modified: 20251109200632671
|
||||
created: 20251109200632671
|
||||
leader: @pmario
|
||||
team: @saqimtiaz
|
||||
|
||||
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
|
||||
|
||||
Tools and resources managed by the Developer Experience Team include:
|
||||
|
||||
* Advising and assisting contributors, particularly new developers
|
||||
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
|
||||
** Development environment setup guides
|
||||
** Code review processes and best practices
|
||||
** Contribution guidelines and documentation
|
||||
* Continuous integration and deployment scripts providing feedback on pull requests
|
||||
* Devising and implementing labelling systems for issues and pull requests
|
||||
* Automation scripts to simplify common development tasks
|
||||
@@ -1,15 +0,0 @@
|
||||
created: 20250909171928024
|
||||
modified: 20251110133437795
|
||||
tags: Community/Team
|
||||
team: @MotovunJack
|
||||
title: Infrastructure Team
|
||||
|
||||
The Infrastructure Team is responsible for maintaining and improving the infrastructure that supports the TiddlyWiki project. This includes the hosting, deployment, and management of the TiddlyWiki websites and services, as well as the tools and systems used by the TiddlyWiki community.
|
||||
|
||||
The infrastructure includes:
|
||||
|
||||
* talk.tiddlywiki.org
|
||||
* github.com/TiddlyWiki
|
||||
* tiddlywiki.com DNS
|
||||
* Netlify account for PR previews
|
||||
* edit.tiddlywiki.com
|
||||
@@ -1,8 +0,0 @@
|
||||
title: MultiWikiServer Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
leader: @Arlen22
|
||||
team:
|
||||
|
||||
The MultiWikiServer development repository is at https://github.com/TiddlyWiki/MultiWikiServer
|
||||
@@ -1,15 +0,0 @@
|
||||
title: Project Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
icon: $:/tiddlywiki/community/icons/project-team
|
||||
leader: @Jermolene
|
||||
team: @saqimtiaz @ericshulman
|
||||
|
||||
The project team is responsible for the overall TiddlyWiki project, its vision, mission and values, and ensuring that it meets the needs of the community.
|
||||
|
||||
Areas of responsibility include:
|
||||
|
||||
* Communicating and demonstrating the vision, mission and values of the project
|
||||
* Continuously improve the development process and practices of the project
|
||||
* more to come...
|
||||
@@ -1,11 +0,0 @@
|
||||
title: Quality Assurance Team
|
||||
created: 20251112125742296
|
||||
modified: 20251112125742296
|
||||
tags: Community/Team
|
||||
team:
|
||||
leader: @Leilei332
|
||||
|
||||
title: Quality Assurance Team
|
||||
|
||||
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
title: Succession Team
|
||||
tags: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
leader: @Jermolene
|
||||
team: @saqimtiaz @ericshulman
|
||||
|
||||
The Succession Team is responsible for ensuring that personnel changes do not impact access to the external infrastructure used by the project.
|
||||
|
||||
* Work with the other teams to ensure that the project has a succession plan for key personnel
|
||||
* Work with the other teams to ensure that they are using the appropriate, community-owned infrastructure
|
||||
* Ensure that the members of the succession team share ownership of the key project resources (eg passwords and user accounts). The Succession Team is not expected to use their access rights apart from managing access in the event of personnel changes
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
title: TiddlyWiki Newsletter Team
|
||||
tags: Community/Team
|
||||
modified: 20251219090709874
|
||||
created: 20250909171928024
|
||||
leader: @Christian_Byron
|
||||
|
||||
The Newsletter Team is responsible for producing the [[TiddlyWiki Newsletter]]. We would love to have your help if you would like to get involved.
|
||||
|
||||
! Audience
|
||||
|
||||
The newsletter is intended for TiddlyWiki end users who do not track all the discussions on https://talk.tiddlywiki.org/.
|
||||
|
||||
Coverage of developer topics such as JavaScript and intricate wikitext should be handled thoughtfully to avoid alienating the core audience of end users.
|
||||
|
||||
Subscribing to the newsletter is intended to give people confidence that they will not miss any important developments.
|
||||
@@ -1,5 +0,0 @@
|
||||
title: Community/Team
|
||||
modified: 20250909171928024
|
||||
created: 20250909171928024
|
||||
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Community Records and Resources
|
||||
|
||||
These raw tiddlers comprise the community records and resources for the TiddlyWiki project. They are packaged as a root directory outside of the usual "editions" folder so that they can be shared with other wikis.
|
||||
@@ -1,15 +0,0 @@
|
||||
title: $:/config/DefaultColourMappings/
|
||||
|
||||
community-card-background: #ffffee
|
||||
community-card-foreground: #441111
|
||||
community-card-dark-shadow: rgba(188, 189, 189, 0.5)
|
||||
community-card-shadow: rgba(212, 212, 213, 0.5)
|
||||
community-card-header-background: #9e3060
|
||||
community-card-header-foreground: #ddddee
|
||||
community-card-team-header-background: #306090
|
||||
community-card-team-header-foreground: #ddeedd
|
||||
community-card-vacancy-header-background: #609030
|
||||
community-card-vacancy-header-foreground: #eedddd
|
||||
community-card-info-background: #f3f38b
|
||||
community-card-info-foreground: #444411
|
||||
community-card-field-name-foreground: #888844
|
||||
@@ -1,168 +0,0 @@
|
||||
title: $:/tiddlywiki/community/cards/Procedures
|
||||
tags: $:/tags/Global
|
||||
|
||||
\procedure community-card-display-jpeg-field(fieldName,mode:"block",default)
|
||||
<$genesis $type={{{ [<mode>match[block]then[div]else[span]] }}} class={{{ tc-community-card-field-image [[tc-community-card-field-image-]addsuffix<fieldName>] +[join[ ]] }}}>
|
||||
<%if [<currentTiddler>has<fieldName>] %>
|
||||
<img src={{{ [<currentTiddler>get<fieldName>addprefix[data:image/jpeg;base64,]] }}} width="32"/>
|
||||
<%else%>
|
||||
<$transclude $tiddler=<<default>> $mode=<<mode>>/>
|
||||
<%endif%>
|
||||
</$genesis>
|
||||
\end community-card-display-jpeg-field
|
||||
|
||||
\procedure community-card-display-transclusion(fieldName,mode:"inline",default)
|
||||
<$genesis $type={{{ [<mode>match[block]then[div]else[span]] }}} class={{{ tc-community-card-field-image [[tc-community-card-field-image-]addsuffix<fieldName>] +[join[ ]] }}}>
|
||||
<%if [<currentTiddler>has<fieldName>] %>
|
||||
<$transclude $tiddler={{{ [<currentTiddler>get<fieldName>] }}} $mode=<<mode>>/>
|
||||
<%else%>
|
||||
<$transclude $tiddler=<<default>> $mode=<<mode>>/>
|
||||
<%endif%>
|
||||
</$genesis>
|
||||
\end community-card-display-transclusion
|
||||
|
||||
\procedure community-card-display-text-field(fieldName,showLabel:"yes",linkPrefix,displayPrefix,mode:"block")
|
||||
<%if [<currentTiddler>has<fieldName>] :or[<fieldName>match[title]] %>
|
||||
<$genesis $type={{{ [<mode>match[block]then[div]else[span]] }}} class={{{ tc-community-card-field-text [[tc-community-card-field-text-]addsuffix<fieldName>] +[join[ ]] }}}>
|
||||
<%if [<showLabel>match[yes]] %>
|
||||
<span class="tc-community-card-field-text-name"><$text text=<<fieldName>>/></span>
|
||||
<%endif%>
|
||||
<%if [<linkPrefix>!match[]] %>
|
||||
<a
|
||||
href={{{ [<currentTiddler>get<fieldName>addprefix<linkPrefix>] }}}
|
||||
class="tc-community-card-field-text-value"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<$text text={{{ [<currentTiddler>get<fieldName>] :else[<fieldName>match[title]then<currentTiddler>] +[addprefix<displayPrefix>] }}}/>
|
||||
</a>
|
||||
<%else%>
|
||||
<span class="tc-community-card-field-text-value">
|
||||
<$text text={{{ [<currentTiddler>get<fieldName>] :else[<fieldName>match[title]then<currentTiddler>] +[addprefix<displayPrefix>] }}}/>
|
||||
</span>
|
||||
<%endif%>
|
||||
</$genesis>
|
||||
<%endif%>
|
||||
\end community-card-display-text-field
|
||||
|
||||
\procedure community-card-person(title)
|
||||
<$let currentTiddler=<<title>>>
|
||||
<div class="tc-community-card">
|
||||
<$link to=<<currentTiddler>> class="tc-community-card-header-link">
|
||||
<div class="tc-community-card-header">
|
||||
<<community-card-display-jpeg-field "avatar" default:"$:/tiddlywiki/community/icons/person">>
|
||||
<<community-card-display-text-field "title" showLabel:"no">>
|
||||
</div>
|
||||
</$link>
|
||||
<div class="tc-community-card-info">
|
||||
<<community-card-display-text-field "fullname">>
|
||||
<<community-card-display-text-field "first-sighting">>
|
||||
<<community-card-display-text-field "talk.tiddlywiki.org" linkPrefix:"https://talk.tiddlywiki.org/u/" displayPrefix:"@">>
|
||||
<<community-card-display-text-field "github" linkPrefix:"https://github.com/" displayPrefix:"@">>
|
||||
<<community-card-display-text-field "linkedin" linkPrefix:"https://">>
|
||||
<<community-card-display-text-field "flickr" linkPrefix:"https://">>
|
||||
<<community-card-display-text-field "homepage" linkPrefix:"https://">>
|
||||
<<community-card-display-text-field "email" linkPrefix:"mailto:">>
|
||||
<%if [all[tiddlers+shadows]tag[Community/Team]sort[title]] :filter[{!!leader}match<..currentTiddler>] +[count[]compare:number:gt[0]] %>
|
||||
<div class="tc-community-card-field-text">
|
||||
<span class="tc-community-card-field-text-name">leader</span>
|
||||
<span class="tc-community-card-field-text-value">
|
||||
<$list filter="[all[tiddlers+shadows]tag[Community/Team]sort[title]] :filter[{!!leader}match<..currentTiddler>]">
|
||||
<$transclude $variable="community-card-pill-team" title=<<currentTiddler>>/>
|
||||
</$list>
|
||||
</span>
|
||||
</div>
|
||||
<%endif%>
|
||||
<%if [all[tiddlers+shadows]tag[Community/Team]sort[title]] :filter[enlist{!!team}match<..currentTiddler>] +[count[]compare:number:gt[0]] %>
|
||||
<div class="tc-community-card-field-text">
|
||||
<span class="tc-community-card-field-text-name">member</span>
|
||||
<span class="tc-community-card-field-text-value">
|
||||
<$list filter="[all[tiddlers+shadows]tag[Community/Team]sort[title]] :filter[enlist{!!team}match<..currentTiddler>]">
|
||||
<$transclude $variable="community-card-pill-team" title=<<currentTiddler>>/>
|
||||
</$list>
|
||||
</span>
|
||||
</div>
|
||||
<%endif%>
|
||||
</div>
|
||||
<div class="tc-community-card-body">
|
||||
<$transclude $tiddler=<<currentTiddler>> $field="text" $mode="block"/>
|
||||
</div>
|
||||
</div>
|
||||
</$let>
|
||||
\end community-card-person
|
||||
|
||||
\procedure community-card-team(title)
|
||||
<$let currentTiddler=<<title>>>
|
||||
<div class="tc-community-card tc-community-card-team">
|
||||
<$link to=<<currentTiddler>> class="tc-community-card-header-link">
|
||||
<div class="tc-community-card-header">
|
||||
<<community-card-display-transclusion fieldName:"icon" default:"$:/tiddlywiki/community/icons/team">>
|
||||
<<community-card-display-text-field "title" showLabel:"no">>
|
||||
</div>
|
||||
</$link>
|
||||
<div class="tc-community-card-info">
|
||||
<div class="tc-community-card-field-text">
|
||||
<span class="tc-community-card-field-text-name">leader</span>
|
||||
<span class="tc-community-card-field-text-value">
|
||||
<%if [<currentTiddler>has[leader]] %>
|
||||
<$transclude $variable="community-card-pill-person" title={{!!leader}}/>
|
||||
<%else%>
|
||||
<$transclude $variable="community-card-vacancy"/>
|
||||
<%endif%>
|
||||
</span>
|
||||
</div>
|
||||
<div class="tc-community-card-field-text">
|
||||
<span class="tc-community-card-field-text-name">team</span>
|
||||
<span class="tc-community-card-field-text-value"><$transclude $variable="community-card-pill-stack-person" personFilter={{!!team}}/></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tc-community-card-body">
|
||||
<$transclude $tiddler=<<currentTiddler>> $field="text" $mode="block"/>
|
||||
</div>
|
||||
</div>
|
||||
</$let>
|
||||
\end community-card-team
|
||||
|
||||
\procedure community-card-pill-person(title)
|
||||
<$let currentTiddler=<<title>>>
|
||||
<$link to=<<currentTiddler>> class="tc-community-card-pill">
|
||||
<<community-card-display-jpeg-field "avatar" default:"$:/tiddlywiki/community/icons/person" mode="inline">>
|
||||
<<community-card-display-text-field "title" showLabel:"no" mode:"inline">>
|
||||
</$link>
|
||||
</$let>
|
||||
\end community-card-pill-person
|
||||
|
||||
\procedure community-card-pill-stack-person(personFilter:"[tag[Community/Person]]")
|
||||
<div class="tc-community-card-pill-stack">
|
||||
<$list filter=<<personFilter>>>
|
||||
<$list-template>
|
||||
<$transclude $variable="community-card-pill-person" title=<<currentTiddler>> mode="block"/>
|
||||
</$list-template>
|
||||
<$list-empty>
|
||||
<$transclude $variable="community-card-vacancy"/>
|
||||
</$list-empty>
|
||||
</$list>
|
||||
</div>
|
||||
\end community-card-pill-stack-person
|
||||
|
||||
\procedure community-card-pill-team(title)
|
||||
<$let currentTiddler=<<title>>>
|
||||
<$link to=<<currentTiddler>> class="tc-community-card-pill">
|
||||
<<community-card-display-transclusion fieldName:"icon" default:"$:/tiddlywiki/community/icons/team">>
|
||||
<<community-card-display-text-field "title" showLabel:"no" mode:"inline">>
|
||||
</$link>
|
||||
</$let>
|
||||
\end community-card-pill-team
|
||||
|
||||
\procedure community-card-vacancy()
|
||||
<$link to="Vacant Positions" class="tc-community-card-pill tc-community-card-pill-vacancy">
|
||||
<span class="tc-community-card-field-image tc-community-card-field-image-avatar">
|
||||
{{$:/core/images/help}}
|
||||
</span>
|
||||
<span class="tc-community-card-field-text tc-community-card-field-text-title">
|
||||
<span class="tc-community-card-field-text-value">
|
||||
Vacant
|
||||
</span>
|
||||
</span>
|
||||
</$link>
|
||||
\end community-card-vacancy
|
||||
@@ -1,158 +0,0 @@
|
||||
title: $:/tiddlywiki/community/cards/Styles
|
||||
tags: $:/tags/Stylesheet
|
||||
|
||||
.tc-community-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
margin-bottom: 8px;
|
||||
background: <<colour community-card-background>>;
|
||||
color: <<colour community-card-foreground>>;
|
||||
fill: <<colour community-card-foreground>>;
|
||||
box-shadow: 0 1px 3px 0 <<colour community-card-shadow>>, 0 0 0 1px <<colour community-card-shadow>>;
|
||||
transition: box-shadow 0.3s ease,transform .3s ease;
|
||||
}
|
||||
|
||||
.tc-community-card:hover {
|
||||
box-shadow: 0 1px 6px 0 <<colour community-card-dark-shadow>>, 0 0 0 1px <<colour community-card-shadow>>;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-header-link {
|
||||
background-color: <<colour community-card-header-background>>;
|
||||
color: <<colour community-card-header-foreground>>;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
.tc-community-card.tc-community-card-team .tc-community-card-header-link {
|
||||
background: <<colour community-card-team-header-background>>;
|
||||
color: <<colour community-card-team-header-foreground>>;
|
||||
fill: <<colour community-card-team-header-foreground>>;
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-header-link:hover {
|
||||
text-decoration: none;
|
||||
background-color: <<colour community-card-header-foreground>>;
|
||||
color: <<colour community-card-header-background>>;
|
||||
}
|
||||
|
||||
.tc-community-card-header {
|
||||
margin: 0;
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.tc-community-card-header .tc-community-card-field-text-title {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tc-community-card-header .tc-community-card-field-image {
|
||||
display: table-row;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.tc-community-card-info {
|
||||
display: table;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
padding: 8px;
|
||||
margin: 0;
|
||||
background-color: <<colour community-card-info-background>>;
|
||||
color: <<colour community-card-info-foreground>>;
|
||||
}
|
||||
|
||||
.tc-community-card-body {
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-field-text {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-field-text-name,
|
||||
.tc-community-card .tc-community-card-field-text-value {
|
||||
display: table-cell;
|
||||
padding: 2px 6px 2px 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-field-text-name {
|
||||
color: <<colour community-card-field-name-foreground>>;
|
||||
white-space: nowrap;
|
||||
text-align: right;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.tc-community-card .tc-community-card-field-text-value {
|
||||
word-break: break-word;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a.tc-community-card-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
width: auto;
|
||||
min-width:0;
|
||||
max-width: none;
|
||||
align-self: auto;
|
||||
font-size: 0.9em;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
background: <<colour community-card-header-background>>;
|
||||
color: <<colour community-card-header-foreground>>;
|
||||
fill: <<colour community-card-header-foreground>>;
|
||||
box-shadow: 0 1px 3px 0 <<colour community-card-shadow>>, 0 0 0 1px <<colour community-card-shadow>>;
|
||||
transition: box-shadow 0.3s ease,transform .3s ease;
|
||||
}
|
||||
|
||||
a.tc-community-card-pill.tc-community-card-pill-vacancy {
|
||||
background: <<colour community-card-vacancy-header-background>>;
|
||||
color: <<colour community-card-vacancy-header-foreground>>;
|
||||
fill: <<colour community-card-vacancy-header-foreground>>;
|
||||
}
|
||||
|
||||
a.tc-community-card-pill:hover {
|
||||
text-decoration: none;
|
||||
box-shadow: 0 1px 6px 0 <<colour community-card-dark-shadow>>, 0 0 0 1px <<colour community-card-shadow>>;
|
||||
transform: translateY(-2px);
|
||||
background: <<colour community-card-header-foreground>>;
|
||||
color: <<colour community-card-header-background>>;
|
||||
fill: <<colour community-card-header-background>>;
|
||||
}
|
||||
|
||||
a.tc-community-card-pill .tc-community-card-field-image img,
|
||||
a.tc-community-card-pill .tc-community-card-field-image svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a.tc-community-card-pill .tc-community-card-field-text {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.tc-community-card-pill-stack {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 4px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
title: $:/tiddlywiki/community/cards/ViewTemplateBodyCascade
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
list-before:
|
||||
|
||||
[tag[Community/Person]then[$:/tiddlywiki/community/cards/ViewTemplateBodyTemplatePerson]]
|
||||
[tag[Community/Team]then[$:/tiddlywiki/community/cards/ViewTemplateBodyTemplateTeam]]
|
||||
@@ -1,3 +0,0 @@
|
||||
title: $:/tiddlywiki/community/cards/ViewTemplateBodyTemplatePerson
|
||||
|
||||
<$transclude $variable="community-card-person" title=<<currentTiddler>>/>
|
||||
@@ -1,3 +0,0 @@
|
||||
title: $:/tiddlywiki/community/cards/ViewTemplateBodyTemplateTeam
|
||||
|
||||
<$transclude $variable="community-card-team" title=<<currentTiddler>>/>
|
||||
@@ -1,7 +0,0 @@
|
||||
title: $:/tiddlywiki/community/icons/person
|
||||
tags: $:/tags/Image
|
||||
|
||||
\parameters (size:"22pt")
|
||||
<svg width=<<size>> height=<<size>> viewBox="0 0 64 64">
|
||||
<path d="M43.127,29.612c-0.879,-0.378 -1.452,-1.25 -1.452,-2.207c-0.006,-0.678 0.27,-1.33 0.761,-1.797c0.147,-0.141 0.29,-0.28 0.397,-0.393c0.753,-0.791 1.416,-1.663 1.978,-2.6c1.392,-2.318 2.126,-4.974 2.126,-7.677c0,-8.196 -6.744,-14.938 -14.938,-14.938c-0.945,0 -1.886,0.088 -2.813,0.266c-5.891,1.031 -10.578,5.586 -11.781,11.446c-1.105,5.016 0.454,10.264 4.118,13.865c0.495,0.469 0.78,1.118 0.792,1.799l0,0.012c0.008,0.966 -0.567,1.848 -1.453,2.23c-5.949,2.466 -10.698,7.172 -13.217,13.099c-1.772,4.059 -2.66,8.45 -2.607,12.88l0,3.192c0,2.858 2.351,5.211 5.212,5.211l43.5,0c2.859,0 5.212,-2.353 5.212,-5.211l-0,-3.225c0.053,-4.427 -0.837,-8.816 -2.611,-12.873c-2.523,-5.922 -7.274,-10.621 -13.224,-13.079Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
@@ -1,7 +0,0 @@
|
||||
title: $:/tiddlywiki/community/icons/project-team
|
||||
tags: $:/tags/Image
|
||||
|
||||
\parameters (size:"22pt")
|
||||
<svg width=<<size>> height=<<size>> viewBox="0 0 64 64">
|
||||
<path d="M24.891,49.399l-3.521,0c-1.398,0 -2.547,-1.15 -2.547,-2.547l0,-1.56c-0.026,-2.165 0.408,-4.311 1.274,-6.295c1.231,-2.897 3.552,-5.197 6.46,-6.402c0.433,-0.187 0.714,-0.618 0.71,-1.09l0,-0.006c-0.006,-0.333 -0.145,-0.65 -0.387,-0.879c-1.791,-1.76 -2.553,-4.325 -2.013,-6.777c0.588,-2.864 2.879,-5.09 5.758,-5.594c0.453,-0.087 0.913,-0.13 1.375,-0.13c4.005,0 7.301,3.295 7.301,7.301c0,1.321 -0.359,2.619 -1.039,3.752c-0.275,0.458 -0.599,0.884 -0.967,1.271c-0.052,0.055 -0.122,0.123 -0.194,0.192c-0.24,0.228 -0.375,0.547 -0.372,0.878c0,0.468 0.28,0.894 0.71,1.079c2.908,1.201 5.23,3.498 6.463,6.392c0.815,1.865 1.248,3.872 1.276,5.904c-0.179,0.006 -0.351,0.007 -0.514,0.003c-0.556,-0.016 -1.375,-0.294 -2.288,-0.512c-1.295,-0.308 -2.719,-0.543 -4.01,-0.396l-0.013,0.001c-1.056,0.128 -2.116,0.325 -3.097,0.76c-0.385,0.171 -1.216,0.753 -1.446,0.916c-1.157,0.297 -2.564,0.475 -3.797,0.312c-0.713,-0.094 -1.402,-0.225 -1.703,-0.778c-0.207,-0.382 -0.181,-0.896 -0.031,-1.565c0.068,-0.3 0.11,-0.593 0.118,-0.842l-0.106,-0.887l-0.212,-0.491l-0.258,-0.36l-0.669,-0.514l-0.832,-0.231l-0.491,0.017l-0.459,0.12l-0.417,0.211l-0.415,0.342l-0.546,0.802l-0.033,0.067c-1.174,2.499 -0.945,4.643 0.013,6.317c0.251,0.437 0.56,0.845 0.919,1.219Zm22.984,-4.722c-0.052,-2.344 -0.566,-4.656 -1.514,-6.805c-1.232,-2.86 -3.339,-5.257 -6.018,-6.845c0.955,-0.816 2.033,-1.473 3.195,-1.949c0.434,-0.187 0.715,-0.618 0.71,-1.09l-0,-0.006c-0.005,-0.333 -0.144,-0.651 -0.386,-0.88c-1.791,-1.76 -2.553,-4.324 -2.013,-6.776c0.587,-2.864 2.878,-5.09 5.758,-5.594c0.453,-0.087 0.913,-0.131 1.375,-0.131c4.005,0 7.3,3.296 7.3,7.301c-0,1.322 -0.359,2.619 -1.038,3.753c-0.276,0.457 -0.6,0.883 -0.968,1.27c-0.052,0.055 -0.121,0.123 -0.194,0.192c-0.24,0.229 -0.375,0.547 -0.372,0.878c-0,0.468 0.28,0.894 0.71,1.079c2.908,1.201 5.229,3.498 6.462,6.392c0.756,1.728 1.184,3.578 1.264,5.458c-0.577,-0.341 -1.293,-0.373 -1.904,-0.07c-0.961,0.475 -1.861,1.117 -2.911,1.371c-0.49,-0.133 -0.983,-0.245 -1.485,-0.308c-0.253,-0.326 -0.536,-0.66 -0.84,-0.911l-0.813,-0.51l-0.752,-0.225c-0.327,-0.051 -0.662,-0.021 -0.974,0.089l-0.67,0.321l-0.569,0.448c-0.403,0.393 -0.733,0.911 -0.979,1.569c-0.202,0.54 -0.344,1.222 -0.492,2.014c-0.244,-0.027 -0.49,-0.047 -0.737,-0.058c-0.333,-0.02 -0.725,-0.006 -1.145,0.023Zm-24.215,-13.651c-2.683,1.591 -4.793,3.994 -6.024,6.861c-1.026,2.332 -1.542,4.857 -1.513,7.405l0,0.59l-11.735,0c-1.397,0 -2.547,-1.15 -2.547,-2.547l0,-1.561c-0.026,-2.165 0.409,-4.31 1.274,-6.295c1.231,-2.897 3.553,-5.197 6.46,-6.401c0.434,-0.187 0.715,-0.618 0.71,-1.09l0,-0.006c-0.005,-0.333 -0.144,-0.651 -0.386,-0.88c-1.791,-1.76 -2.553,-4.324 -2.013,-6.776c0.588,-2.864 2.879,-5.09 5.758,-5.594c0.453,-0.087 0.914,-0.131 1.375,-0.131c4.005,0 7.301,3.296 7.301,7.301c0,1.322 -0.359,2.619 -1.039,3.753c-0.275,0.457 -0.6,0.883 -0.967,1.27c-0.052,0.055 -0.122,0.123 -0.194,0.192c-0.24,0.228 -0.375,0.547 -0.372,0.878c0,0.468 0.28,0.894 0.71,1.079c1.164,0.476 2.246,1.135 3.202,1.952Zm29.027,33.111c-1.417,-0.04 -2.04,-0.037 -2.761,-1.223l-0.563,0.016c-0.654,-0.029 -0.381,-0.016 -0.818,-0.038c-0.73,-0.028 -0.613,-0.722 -0.742,-1.089c-0.205,-1.244 0.272,-2.494 0.257,-3.739c-0.005,-0.442 -0.63,-2.005 -0.854,-2.564c-0.7,0.131 -1.404,0.157 -2.114,0.192c-1.637,-0.004 -3.263,-0.205 -4.878,-0.459c-0.314,1.299 -1.249,3.118 -0.476,4.439c0.938,1.366 1.596,1.745 2.617,1.827c1.02,0.082 1.251,1.234 1.004,1.646c-0.219,0.284 -0.603,0.336 -0.929,0.405l-0.653,0.03c-0.513,-0.017 -0.973,-0.155 -1.43,-0.369c-0.765,-0.427 -1.554,-1.314 -2.141,-1.951c0.137,0.254 0.218,0.751 0.095,0.982c-0.347,0.491 -1.847,0.488 -2.534,0.183c-0.78,-0.347 -2.665,-2.781 -2.957,-4.604c0.776,-1.467 1.905,-2.744 2.477,-4.341c-1.246,-0.795 -1.913,-2.089 -1.827,-3.555l0.032,-0.17c-1.226,0.23 -0.59,0.144 -1.909,0.244c-4.2,-0.013 -7.893,-2.86 -5.813,-7.286c0.135,-0.262 0.263,-0.5 0.493,-0.386c0.184,0.091 0.157,0.457 0.065,0.863c-1.189,5.288 4.621,5.329 8.192,4.35c0.355,-0.097 1.06,-0.751 1.548,-0.968c0.798,-0.354 1.665,-0.498 2.524,-0.602c2.139,-0.244 4.709,0.883 6.015,0.92c1.306,0.037 3.164,-0.313 4.305,-0.239c0.827,0.037 1.64,0.187 2.438,0.4c0.517,-2.519 0.554,-4.374 1.779,-4.804c0.719,0.113 1.273,1.093 1.683,1.617l0.002,-0c0.835,-0.033 1.63,0.178 2.42,0.414c1.431,-0.203 2.631,-1.007 3.895,-1.632c-0.004,0.02 -0.025,0.027 -0.037,0.04c-1.244,1.005 -1.417,2.706 -1.271,4.278c0.054,0.816 -0.176,1.702 -0.461,2.538c-0.534,1.361 -1.564,2.796 -2.759,2.722c-0.452,-0.014 -0.715,-0.27 -1.051,-0.543c-0.065,0.553 -0.321,1.047 -0.568,1.536c-0.57,1.086 -2.06,1.564 -3.44,2.723c-1.379,1.159 0.442,5.297 0.883,6.052c0.442,0.754 1.674,1.03 1.196,1.71c-0.147,0.225 -0.37,0.305 -0.609,0.393l-0.325,0.042Zm-15.735,-3.096l0.206,0.06c0.258,-0.115 0.778,0.064 1.054,0.151c-0.508,-0.563 -1.273,-1.389 -1.824,-1.91c-0.181,-0.631 -0.103,-1.266 -0.065,-1.91l0.008,-0.053c-0.217,0.515 -0.493,1.016 -0.641,1.559c-0.173,0.732 0.771,1.522 1.137,1.975l0.125,0.128Z"/>
|
||||
</svg>
|
||||
@@ -1,9 +0,0 @@
|
||||
title: $:/tiddlywiki/community/icons/team
|
||||
tags: $:/tags/Image
|
||||
|
||||
\parameters (size:"22pt")
|
||||
<svg width=<<size>> height=<<size>> viewBox="0 0 64 64">
|
||||
<path d="M37.439,32.592c-0.43,-0.185 -0.71,-0.611 -0.71,-1.079c-0.003,-0.331 0.132,-0.65 0.372,-0.878c0.072,-0.069 0.142,-0.137 0.194,-0.192c0.368,-0.387 0.692,-0.813 0.967,-1.271c0.68,-1.133 1.039,-2.431 1.039,-3.752c-0,-4.006 -3.296,-7.301 -7.301,-7.301c-0.462,-0 -0.922,0.043 -1.375,0.13c-2.879,0.504 -5.17,2.73 -5.758,5.594c-0.54,2.452 0.222,5.017 2.013,6.777c0.242,0.229 0.381,0.546 0.387,0.879l-0,0.006c0.004,0.472 -0.277,0.903 -0.71,1.09c-2.908,1.205 -5.229,3.505 -6.46,6.402c-0.866,1.984 -1.3,4.13 -1.274,6.295l-0,1.56c-0,1.397 1.149,2.547 2.547,2.547c-0,-0 0,-0 0,-0l21.261,-0c1.397,-0 2.547,-1.15 2.547,-2.547l-0,-1.576c0.026,-2.164 -0.409,-4.309 -1.276,-6.292c-1.233,-2.894 -3.555,-5.191 -6.463,-6.392Z" style="fill-rule:nonzero;"/>
|
||||
<path d="M60.882,35.466c-1.233,-2.894 -3.554,-5.191 -6.462,-6.392c-0.43,-0.185 -0.71,-0.611 -0.71,-1.079c-0.003,-0.331 0.132,-0.649 0.372,-0.878c0.073,-0.069 0.142,-0.137 0.194,-0.192c0.368,-0.387 0.692,-0.813 0.968,-1.27c0.679,-1.134 1.038,-2.431 1.038,-3.753c0,-4.005 -3.295,-7.301 -7.3,-7.301c-0.462,0 -0.922,0.044 -1.375,0.131c-2.88,0.504 -5.171,2.73 -5.758,5.594c-0.54,2.452 0.222,5.016 2.013,6.776c0.242,0.229 0.381,0.547 0.386,0.88l-0,0.006c0.005,0.472 -0.276,0.903 -0.71,1.09c-1.162,0.476 -2.24,1.133 -3.195,1.949c2.679,1.588 4.786,3.985 6.018,6.845c1.029,2.332 1.546,4.857 1.517,7.405l-0,0.605l11.734,-0c1.397,-0 2.547,-1.15 2.547,-2.547l-0,-1.576c0.026,-2.165 -0.409,-4.31 -1.277,-6.293Z" style="fill-rule:nonzero;"/>
|
||||
<path d="M23.66,31.026c-0.956,-0.817 -2.038,-1.476 -3.202,-1.952c-0.43,-0.185 -0.71,-0.611 -0.71,-1.079c-0.003,-0.331 0.132,-0.65 0.372,-0.878c0.072,-0.069 0.142,-0.137 0.194,-0.192c0.367,-0.387 0.692,-0.813 0.967,-1.27c0.68,-1.134 1.039,-2.431 1.039,-3.753c-0,-4.005 -3.296,-7.301 -7.301,-7.301c-0.461,0 -0.922,0.044 -1.375,0.131c-2.879,0.504 -5.17,2.73 -5.758,5.594c-0.54,2.452 0.222,5.016 2.013,6.776c0.242,0.229 0.381,0.547 0.386,0.88l0,0.006c0.005,0.472 -0.276,0.903 -0.71,1.09c-2.907,1.204 -5.229,3.504 -6.46,6.401c-0.865,1.985 -1.3,4.13 -1.274,6.295c0,0 0,1.561 0,1.561c0,1.397 1.15,2.547 2.547,2.547c-0,-0 11.735,-0 11.735,-0l0,-0.59c-0.029,-2.548 0.487,-5.073 1.513,-7.405c1.231,-2.867 3.341,-5.27 6.024,-6.861Z" style="fill-rule:nonzero;"/>
|
||||
</svg>
|
||||
@@ -1,176 +0,0 @@
|
||||
/*\
|
||||
title: $:/core/modules/commander.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
The $tw.Commander class is a command interpreter
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Parse a sequence of commands
|
||||
commandTokens: an array of command string tokens
|
||||
wiki: reference to the wiki store object
|
||||
streams: {output:, error:}, each of which has a write(string) method
|
||||
callback: a callback invoked as callback(err) where err is null if there was no error
|
||||
*/
|
||||
var Commander = function(commandTokens,callback,wiki,streams) {
|
||||
var path = require("path");
|
||||
this.commandTokens = commandTokens;
|
||||
this.nextToken = 0;
|
||||
this.callback = callback;
|
||||
this.wiki = wiki;
|
||||
this.streams = streams;
|
||||
this.outputPath = path.resolve($tw.boot.wikiPath,$tw.config.wikiOutputSubDir);
|
||||
};
|
||||
|
||||
/*
|
||||
Log a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.log = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str + "\n");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Write a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.write = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Add a string of tokens to the command queue
|
||||
*/
|
||||
Commander.prototype.addCommandTokens = function(commandTokens) {
|
||||
var params = commandTokens.slice(0);
|
||||
params.unshift(0);
|
||||
params.unshift(this.nextToken);
|
||||
Array.prototype.splice.apply(this.commandTokens,params);
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the sequence of commands and invoke a callback on completion
|
||||
*/
|
||||
Commander.prototype.execute = function() {
|
||||
this.executeNextCommand();
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the next command in the sequence
|
||||
*/
|
||||
Commander.prototype.executeNextCommand = function() {
|
||||
var self = this;
|
||||
// Invoke the callback if there are no more commands
|
||||
if(this.nextToken >= this.commandTokens.length) {
|
||||
this.callback(null);
|
||||
} else {
|
||||
// Get and check the command token
|
||||
var commandName = this.commandTokens[this.nextToken++];
|
||||
if(commandName.substr(0,2) !== "--") {
|
||||
this.callback("Missing command: " + commandName);
|
||||
} else {
|
||||
commandName = commandName.substr(2); // Trim off the --
|
||||
// Accumulate the parameters to the command
|
||||
var params = [];
|
||||
while(this.nextToken < this.commandTokens.length &&
|
||||
this.commandTokens[this.nextToken].substr(0,2) !== "--") {
|
||||
params.push(this.commandTokens[this.nextToken++]);
|
||||
}
|
||||
// Get the command info
|
||||
var command = $tw.commands[commandName],
|
||||
c,err;
|
||||
if(!command) {
|
||||
this.callback("Unknown command: " + commandName);
|
||||
} else {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write("Executing command: " + commandName + " " + params.join(" ") + "\n");
|
||||
}
|
||||
// Parse named parameters if required
|
||||
if(command.info.namedParameterMode) {
|
||||
params = this.extractNamedParameters(params,command.info.mandatoryParameters);
|
||||
if(typeof params === "string") {
|
||||
return this.callback(params);
|
||||
}
|
||||
}
|
||||
if(command.info.synchronous) {
|
||||
// Synchronous command (await thenables)
|
||||
c = new command.Command(params,this);
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||
} else if(err) {
|
||||
this.callback(err);
|
||||
} else {
|
||||
this.executeNextCommand();
|
||||
}
|
||||
} else {
|
||||
// Asynchronous command (await thenables)
|
||||
c = new command.Command(params,this,function(err) {
|
||||
if(err) {
|
||||
self.callback(err);
|
||||
} else {
|
||||
self.executeNextCommand();
|
||||
}
|
||||
});
|
||||
err = c.execute();
|
||||
if(err && typeof err.then === "function") {
|
||||
err.then(e => { if(e) this.callback(e); });
|
||||
} else if(err) {
|
||||
this.callback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Given an array of parameter strings `params` in name:value format, and an array of mandatory parameter names in `mandatoryParameters`, returns a hashmap of values or a string if error
|
||||
*/
|
||||
Commander.prototype.extractNamedParameters = function(params,mandatoryParameters) {
|
||||
mandatoryParameters = mandatoryParameters || [];
|
||||
var errors = [],
|
||||
paramsByName = Object.create(null);
|
||||
// Extract the parameters
|
||||
$tw.utils.each(params,function(param) {
|
||||
var index = param.indexOf("=");
|
||||
if(index < 1) {
|
||||
errors.push("malformed named parameter: '" + param + "'");
|
||||
}
|
||||
paramsByName[param.slice(0,index)] = $tw.utils.trim(param.slice(index+1));
|
||||
});
|
||||
// Check the mandatory parameters are present
|
||||
$tw.utils.each(mandatoryParameters,function(mandatoryParameter) {
|
||||
if(!$tw.utils.hop(paramsByName,mandatoryParameter)) {
|
||||
errors.push("missing mandatory parameter: '" + mandatoryParameter + "'");
|
||||
}
|
||||
});
|
||||
// Return any errors
|
||||
if(errors.length > 0) {
|
||||
return errors.join(" and\n");
|
||||
} else {
|
||||
return paramsByName;
|
||||
}
|
||||
};
|
||||
|
||||
Commander.initCommands = function(moduleType) {
|
||||
moduleType = moduleType || "command";
|
||||
$tw.commands = {};
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
|
||||
var c = $tw.commands[module.info.name] = {};
|
||||
// Add the methods defined by the module
|
||||
for(var f in module) {
|
||||
if($tw.utils.hop(module,f)) {
|
||||
c[f] = module[f];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.Commander = Commander;
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
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
|
||||
@@ -1,73 +0,0 @@
|
||||
/*\
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
/*\
|
||||
title: $:/core-modules/modules/utils/base64.js
|
||||
type: application/javascript
|
||||
module-type: utils-node
|
||||
|
||||
Base64 UTF-8 utlity functions.
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const{ TextEncoder, TextDecoder } = require("node:util");
|
||||
|
||||
exports.btoa = binstr => Buffer.from(binstr, "binary").toString("base64");
|
||||
|
||||
exports.atob = b64 => Buffer.from(b64, "base64").toString("binary");
|
||||
|
||||
function base64ToBytes(base64) {
|
||||
const binString = exports.atob(base64);
|
||||
return Uint8Array.from(binString, m => m.codePointAt(0));
|
||||
};
|
||||
|
||||
function bytesToBase64(bytes) {
|
||||
const binString = Array.from(bytes, byte => String.fromCodePoint(byte)).join("");
|
||||
return exports.btoa(binString);
|
||||
};
|
||||
|
||||
exports.base64EncodeUtf8 = str => bytesToBase64(new TextEncoder().encode(str));
|
||||
|
||||
exports.base64DecodeUtf8 = str => new TextDecoder().decode(base64ToBytes(str));
|
||||
@@ -4,5 +4,4 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
|
||||
|
||||
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
||||
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
||||
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
|
||||
* [[diff-match-patch-es by antfu|https://github.com/antfu/diff-match-patch-es]]
|
||||
* [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]]
|
||||
|
||||
@@ -131,14 +131,15 @@ Saving/GitService/Gitea/Caption: Gitea Saver
|
||||
Saving/GitService/Gitea/Password: Personal access token for API (via Gitea’s web interface: `Settings | Applications | Generate New Token`)
|
||||
Saving/TiddlySpot/Advanced/Heading: Advanced Settings
|
||||
Saving/TiddlySpot/BackupDir: Backup Directory
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlyHost Control Panel
|
||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
||||
Saving/TiddlySpot/Backups: Backups
|
||||
Saving/TiddlySpot/Caption: ~TiddlyHost Saver
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to [[TiddlyHost|https://tiddlyhost.com]] or a compatible remote server. See [[here|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]] for information on ~TiddlyHost saving configuration
|
||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
||||
Saving/TiddlySpot/Description: These settings are only used when saving to [[TiddlySpot|http://tiddlyspot.com]], [[TiddlyHost|https://tiddlyhost.com]], or a compatible remote server. See [[here|https://github.com/simonbaird/tiddlyhost/wiki/TiddlySpot-Saver-configuration-for-Tiddlyhost-and-Tiddlyspot]] for information on ~TiddlySpot and ~TiddlyHost saving configuration.
|
||||
Saving/TiddlySpot/Filename: Upload Filename
|
||||
Saving/TiddlySpot/Heading: ~TiddlyHost
|
||||
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
|
||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
||||
Saving/TiddlySpot/Hint: //The server URL defaults to `http://<wikiname>.tiddlyspot.com/store.cgi` and can be changed to use a custom server address, e.g. `http://example.com/store.php`.//
|
||||
Saving/TiddlySpot/Password: Password
|
||||
Saving/TiddlySpot/ReadOnly: Note that [[TiddlySpot|http://tiddlyspot.com]] no longer allows the creation of new sites. For new sites, you can use [[TiddlyHost|https://tiddlyhost.com]], a new hosting service that replaces ~TiddlySpot.
|
||||
Saving/TiddlySpot/ServerURL: Server URL
|
||||
Saving/TiddlySpot/UploadDir: Upload Directory
|
||||
Saving/TiddlySpot/UserName: Wiki Name
|
||||
@@ -147,7 +148,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
||||
Settings/AutoSave/Enabled/Description: Save changes automatically
|
||||
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||
Settings/CamelCase/Hint: Requires reload to take effect
|
||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||
Settings/Caption: Settings
|
||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||
@@ -189,8 +190,6 @@ Settings/DefaultSidebarTab/Caption: Default Sidebar Tab
|
||||
Settings/DefaultSidebarTab/Hint: Specify which sidebar tab is displayed by default
|
||||
Settings/DefaultMoreSidebarTab/Caption: Default More Sidebar Tab
|
||||
Settings/DefaultMoreSidebarTab/Hint: Specify which More sidebar tab is displayed by default
|
||||
Settings/DefaultTiddlerInfoTab/Caption: Default Tiddler Info Tab
|
||||
Settings/DefaultTiddlerInfoTab/Hint: Specify which tab is displayed by default when tiddler info panel is opened
|
||||
Settings/LinkToBehaviour/Caption: Tiddler Opening Behaviour
|
||||
Settings/LinkToBehaviour/InsideRiver/Hint: Navigation from //within// the story river
|
||||
Settings/LinkToBehaviour/OutsideRiver/Hint: Navigation from //outside// the story river
|
||||
@@ -252,6 +251,3 @@ ViewTemplateSubtitle/Caption: View Template Subtitle
|
||||
ViewTemplateSubtitle/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the subtitle of a tiddler.
|
||||
ViewTemplateTags/Caption: View Template Tags
|
||||
ViewTemplateTags/Hint: This rule cascade is used by the default view template to dynamically choose the template for displaying the tags area of a tiddler.
|
||||
WikiInformation/Caption: Wiki Information
|
||||
WikiInformation/Hint: This page summarises high level information about the configuration of this ~TiddlyWiki. It is designed to enable users to quickly share relevant aspects of the configuration of their ~TiddlyWiki with others, for example when seeking help in one of the forums. No private or personal information is included, and nothing is shared without being explicitly copied and pasted elsewhere
|
||||
WikiInformation/Drag/Caption: Drag this link to copy this tool to another wiki
|
||||
@@ -4,12 +4,12 @@ _canonical_uri: The full URI of an external image tiddler
|
||||
author: Name of the author of a plugin
|
||||
bag: The name of the bag from which a tiddler came
|
||||
caption: The text to be displayed on a tab or button
|
||||
class: The CSS class applied to a tiddler when rendering it. Also used for Modals
|
||||
class: The CSS class applied to a tiddler when rendering it - see [[Custom styles by user-class]]. Also used for [[Modals]]
|
||||
code-body: The view template will display the tiddler as code if set to ''yes''
|
||||
color: The CSS color value associated with a tiddler
|
||||
component: The name of the component responsible for an alert tiddler
|
||||
component: The name of the component responsible for an [[alert tiddler|AlertMechanism]]
|
||||
core-version: For a plugin, indicates what version of TiddlyWiki with which it is compatible
|
||||
current-tiddler: Used to cache the top tiddler in a history list
|
||||
current-tiddler: Used to cache the top tiddler in a [[history list|HistoryMechanism]]
|
||||
created: The date a tiddler was created
|
||||
creator: The name of the person who created a tiddler
|
||||
dependents: For a plugin, lists the dependent plugin titles
|
||||
|
||||
8
core/language/en-GB/Help/echo.tid
Normal file
8
core/language/en-GB/Help/echo.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/language/Help/echo
|
||||
description: Displays all the passed arguments
|
||||
|
||||
Displays all the passed arguments to a command. Useful for debugging.
|
||||
|
||||
```
|
||||
--echo <text> *
|
||||
```
|
||||
@@ -1,6 +1,5 @@
|
||||
title: $:/language/
|
||||
|
||||
Alerts: Alerts
|
||||
AboveStory/ClassicPlugin/Warning: It looks like you are trying to load a plugin designed for ~TiddlyWiki Classic. Please note that [[these plugins do not work with TiddlyWiki version 5.x.x|https://tiddlywiki.com/#TiddlyWikiClassic]]. ~TiddlyWiki Classic plugins detected:
|
||||
BinaryWarning/Prompt: This tiddler contains binary data
|
||||
ClassicWarning/Hint: This tiddler is written in TiddlyWiki Classic wiki text format, which is not fully compatible with TiddlyWiki version 5. See https://tiddlywiki.com/static/Upgrading.html for more details.
|
||||
@@ -30,7 +29,6 @@ Error/DeserializeOperator/MissingOperand: Filter Error: Missing operand for 'des
|
||||
Error/DeserializeOperator/UnknownDeserializer: Filter Error: Unknown deserializer provided as operand for the 'deserialize' operator
|
||||
Error/Filter: Filter error
|
||||
Error/FilterSyntax: Syntax error in filter expression
|
||||
Error/FilterPragma: Filter Error: Unknown filter pragma
|
||||
Error/FilterRunPrefix: Filter Error: Unknown prefix for filter run
|
||||
Error/IsFilterOperator: Filter Error: Unknown parameter for the 'is' filter operator
|
||||
Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
|
||||
|
||||
275
core/modules/commander.js
Normal file
275
core/modules/commander.js
Normal file
@@ -0,0 +1,275 @@
|
||||
/*\
|
||||
title: $:/core/modules/commander.js
|
||||
type: application/javascript
|
||||
module-type: global
|
||||
|
||||
The $tw.Commander class is a command interpreter
|
||||
|
||||
\*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Parse a sequence of commands
|
||||
commandTokens: an array of command string tokens
|
||||
wiki: reference to the wiki store object
|
||||
streams: {output:, input:, error:}
|
||||
callback: a callback invoked as callback(err) where err is null if there was no error
|
||||
*/
|
||||
var Commander = function(commandTokens,callback,wiki,streams) {
|
||||
var path = require("path");
|
||||
this.commandTokens = commandTokens;
|
||||
this.nextToken = 0;
|
||||
this.callback = callback;
|
||||
this.wiki = wiki;
|
||||
this.streams = streams;
|
||||
this.outputPath = path.resolve($tw.boot.wikiPath,$tw.config.wikiOutputSubDir);
|
||||
};
|
||||
|
||||
/*
|
||||
Log a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.log = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str + "\n");
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Write a string if verbose flag is set
|
||||
*/
|
||||
Commander.prototype.write = function(str) {
|
||||
if(this.verbose) {
|
||||
this.streams.output.write(str);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Add a string of tokens to the command queue
|
||||
*/
|
||||
Commander.prototype.addCommandTokens = function(commandTokens) {
|
||||
var params = commandTokens.slice(0);
|
||||
params.unshift(0);
|
||||
params.unshift(this.nextToken);
|
||||
Array.prototype.splice.apply(this.commandTokens,params);
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the sequence of commands and invoke a callback on completion
|
||||
*/
|
||||
Commander.prototype.execute = function() {
|
||||
this.executeNextCommand();
|
||||
};
|
||||
|
||||
/*
|
||||
Returns the next string token without consuming it, or null if there are none left. Callback invoked(err,data)
|
||||
*/
|
||||
Commander.prototype.peekNextToken = function(callback) {
|
||||
var self = this;
|
||||
if(this.nextToken >= this.commandTokens.length) {
|
||||
return callback(null,null);
|
||||
} else {
|
||||
return this.stringifyToken(this.nextToken,function(err,data) {
|
||||
if(!err) {
|
||||
// Save the stringified token for next time so that we don't run prompts twice
|
||||
self.commandTokens[self.nextToken] = data;
|
||||
}
|
||||
callback(err,data);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns and consumes the next string token, or null if there are none left. Callback invoked(err,data)
|
||||
*/
|
||||
Commander.prototype.getNextToken = function(callback) {
|
||||
if(this.nextToken >= this.commandTokens.length) {
|
||||
return callback(null,null);
|
||||
} else {
|
||||
return this.stringifyToken(this.nextToken++,callback);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Returns and consumes the string tokens until the end of the token stream or the first token that starts with "--".
|
||||
Callback invoked(err,tokenArray)
|
||||
*/
|
||||
Commander.prototype.getTokensUntilCommand = function(callback) {
|
||||
var self = this,
|
||||
tokens = [];
|
||||
function processNextToken() {
|
||||
self.peekNextToken(function(err,data) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
if(data === null || data.substr(0,2) === "--") {
|
||||
return callback(null,tokens);
|
||||
} else {
|
||||
self.getNextToken(function(err,data) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
tokens.push(data);
|
||||
processNextToken();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
processNextToken();
|
||||
};
|
||||
|
||||
/*
|
||||
Returns a specified stringified token, or null if the index does not exist. Callback invoked(err,data)
|
||||
*/
|
||||
Commander.prototype.stringifyToken = function(index,callback) {
|
||||
var self = this;
|
||||
if(index >= this.commandTokens.length) {
|
||||
return callback(null,null);
|
||||
} else {
|
||||
var token = this.commandTokens[index];
|
||||
if(typeof token === "string") {
|
||||
return callback(null,token);
|
||||
} else if(typeof token === "object") {
|
||||
switch(token.type) {
|
||||
case "filter":
|
||||
return callback(null,this.wiki.filterTiddlers(token.text)[0] || "");
|
||||
case "wikify":
|
||||
return callback(null,this.wiki.renderText("text/plain","text/vnd.tiddlywiki",token.text,{
|
||||
parseAsInline: false,
|
||||
parentWidget: $tw.rootWidget
|
||||
}));
|
||||
case "prompt":
|
||||
$tw.utils.terminalQuestion({
|
||||
promptText: token.prompt || "Please enter a value",
|
||||
defaultResult: token["default"] || "",
|
||||
callback: function(err,userText) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
} else {
|
||||
if(token.transformFilter) {
|
||||
userText = self.wiki.filterTiddlers(token.transformFilter,null,self.wiki.makeTiddlerIterator([userText]))[0] || "";
|
||||
}
|
||||
callback(null,userText);
|
||||
}
|
||||
},
|
||||
input: self.streams.input,
|
||||
output: self.streams.output,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw "Unknown dynamic command token type: " + token.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Execute the next command in the sequence
|
||||
*/
|
||||
Commander.prototype.executeNextCommand = function() {
|
||||
var self = this;
|
||||
// Get and check the command token
|
||||
var commandName = this.getNextToken(function(err,commandName) {
|
||||
if(err) {
|
||||
return self.callback(err);
|
||||
}
|
||||
if(!commandName) {
|
||||
return self.callback(null);
|
||||
}
|
||||
if(commandName.substr(0,2) !== "--") {
|
||||
return self.callback("Missing command: " + commandName);
|
||||
} else {
|
||||
commandName = commandName.substr(2); // Trim off the --
|
||||
// Get the parameters to the command
|
||||
self.getTokensUntilCommand(function(err,params) {
|
||||
if(err) {
|
||||
return self.callback(err);
|
||||
}
|
||||
var command = $tw.commands[commandName],
|
||||
c,err;
|
||||
if(!command) {
|
||||
self.callback("Unknown command: " + commandName);
|
||||
} else {
|
||||
if(self.verbose) {
|
||||
self.streams.output.write("Executing command: " + commandName + " " + params.join(" ") + "\n");
|
||||
}
|
||||
// Parse named parameters if required
|
||||
if(command.info.namedParameterMode) {
|
||||
params = self.extractNamedParameters(params,command.info.mandatoryParameters);
|
||||
if(typeof params === "string") {
|
||||
return self.callback(params);
|
||||
}
|
||||
}
|
||||
if(command.info.synchronous) {
|
||||
// Synchronous command
|
||||
c = new command.Command(params,self);
|
||||
err = c.execute();
|
||||
if(err) {
|
||||
self.callback(err);
|
||||
} else {
|
||||
self.executeNextCommand();
|
||||
}
|
||||
} else {
|
||||
// Asynchronous command
|
||||
c = new command.Command(params,self,function(err) {
|
||||
if(err) {
|
||||
self.callback(err);
|
||||
} else {
|
||||
self.executeNextCommand();
|
||||
}
|
||||
});
|
||||
err = c.execute();
|
||||
if(err) {
|
||||
self.callback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Given an array of parameter strings `params` in name:value format, and an array of mandatory parameter names in `mandatoryParameters`, returns a hashmap of values or a string if error
|
||||
*/
|
||||
Commander.prototype.extractNamedParameters = function(params,mandatoryParameters) {
|
||||
mandatoryParameters = mandatoryParameters || [];
|
||||
var errors = [],
|
||||
paramsByName = Object.create(null);
|
||||
// Extract the parameters
|
||||
$tw.utils.each(params,function(param) {
|
||||
var index = param.indexOf("=");
|
||||
if(index < 1) {
|
||||
errors.push("malformed named parameter: '" + param + "'");
|
||||
}
|
||||
paramsByName[param.slice(0,index)] = $tw.utils.trim(param.slice(index+1));
|
||||
});
|
||||
// Check the mandatory parameters are present
|
||||
$tw.utils.each(mandatoryParameters,function(mandatoryParameter) {
|
||||
if(!$tw.utils.hop(paramsByName,mandatoryParameter)) {
|
||||
errors.push("missing mandatory parameter: '" + mandatoryParameter + "'");
|
||||
}
|
||||
});
|
||||
// Return any errors
|
||||
if(errors.length > 0) {
|
||||
return errors.join(" and\n");
|
||||
} else {
|
||||
return paramsByName;
|
||||
}
|
||||
};
|
||||
|
||||
Commander.initCommands = function(moduleType) {
|
||||
moduleType = moduleType || "command";
|
||||
$tw.commands = {};
|
||||
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
|
||||
var c = $tw.commands[module.info.name] = {};
|
||||
// Add the methods defined by the module
|
||||
for(var f in module) {
|
||||
if($tw.utils.hop(module,f)) {
|
||||
c[f] = module[f];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.Commander = Commander;
|
||||
32
core/modules/commands/echo.js
Normal file
32
core/modules/commands/echo.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/echo.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Command to echo input parameters
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "echo",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander) {
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
this.commander.streams.output.write(JSON.stringify(this.params,null,4) + "\n");
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -76,7 +76,6 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
|
||||
"$:/boot/boot.js",
|
||||
"$:/boot/bootprefix.js",
|
||||
"$:/core",
|
||||
"$:/core-server",
|
||||
"$:/library/sjcl.js",
|
||||
"$:/temp/info-plugin"
|
||||
];
|
||||
@@ -34,7 +34,7 @@ function FramedEngine(options) {
|
||||
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||
this.iframeDoc.open();
|
||||
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
|
||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
||||
this.iframeDoc.close();
|
||||
// Style the iframe
|
||||
this.iframeNode.className = this.dummyTextArea.className;
|
||||
@@ -156,8 +156,8 @@ Fix the height of textarea to fit content
|
||||
FramedEngine.prototype.fixHeight = function() {
|
||||
// Make sure styles are updated
|
||||
this.copyStyles();
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if(this.widget.editTag === "textarea" && !this.widget.editRows) {
|
||||
// Adjust height
|
||||
if(this.widget.editTag === "textarea") {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
var newHeight = $tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
|
||||
@@ -100,8 +100,7 @@ SimpleEngine.prototype.getText = function() {
|
||||
Fix the height of textarea to fit content
|
||||
*/
|
||||
SimpleEngine.prototype.fixHeight = function() {
|
||||
// If .editRows is initialised, it takes precedence
|
||||
if((this.widget.editTag === "textarea") && !this.widget.editRows) {
|
||||
if(this.widget.editTag === "textarea") {
|
||||
if(this.widget.editAutoHeight) {
|
||||
if(this.domNode && !this.domNode.isTiddlyWikiFakeDom) {
|
||||
$tw.utils.resizeTextAreaToFit(this.domNode,this.widget.editMinHeight);
|
||||
|
||||
@@ -68,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||
// Fix height
|
||||
this.engine.fixHeight();
|
||||
// Focus if required
|
||||
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
|
||||
if(this.editFocus === "true" || this.editFocus === "yes") {
|
||||
this.engine.focus();
|
||||
}
|
||||
// Add widget message listeners
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*\
|
||||
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++);
|
||||
}
|
||||
// Get the operator name
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
|
||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
||||
if(nextBracketPos === -1) {
|
||||
throw "Missing [ in filter expression";
|
||||
}
|
||||
@@ -79,17 +79,13 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
operand.variable = true;
|
||||
nextBracketPos = filterString.indexOf(">",p);
|
||||
break;
|
||||
case "(": // Round brackets
|
||||
operand.multiValuedVariable = true;
|
||||
nextBracketPos = filterString.indexOf(")",p);
|
||||
break;
|
||||
case "/": // regexp brackets
|
||||
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||
rexMatch = rex.exec(filterString.substring(p));
|
||||
if(rexMatch) {
|
||||
operator.regexp = new RegExp(rexMatch[1], rexMatch[2]);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
// DEPRECATION WARNING
|
||||
console.log("WARNING: Filter",operator.operator,"has a deprecated regexp operand",operator.regexp);
|
||||
nextBracketPos = p + rex.lastIndex - 1;
|
||||
}
|
||||
else {
|
||||
@@ -116,7 +112,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||
// Check for multiple operands
|
||||
while(filterString.charAt(p) === ",") {
|
||||
p++;
|
||||
if(/^[\[\{<\/\(]/.test(filterString.substring(p))) {
|
||||
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
||||
nextBracketPos = p;
|
||||
p++;
|
||||
parseOperand(filterString.charAt(nextBracketPos));
|
||||
@@ -145,17 +141,7 @@ exports.parseFilter = function(filterString) {
|
||||
p = 0, // Current position in the filter string
|
||||
match;
|
||||
var whitespaceRegExp = /(\s+)/mg,
|
||||
// Groups:
|
||||
// 1 - pragma
|
||||
// 2 - pragma suffix
|
||||
// 3 - entire filter run prefix
|
||||
// 4 - filter run prefix name
|
||||
// 5 - filter run prefix suffixes
|
||||
// 6 - opening square bracket following filter run prefix
|
||||
// 7 - double quoted string following filter run prefix
|
||||
// 8 - single quoted string following filter run prefix
|
||||
// 9 - anything except for whitespace and square brackets
|
||||
operandRegExp = /(?:::(\w+)(?:\:(\w+))?(?=\s|$)|((?:\+|\-|~|(?:=>?)|:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+)))/mg;
|
||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||
while(p < filterString.length) {
|
||||
// Skip any whitespace
|
||||
whitespaceRegExp.lastIndex = p;
|
||||
@@ -166,53 +152,41 @@ exports.parseFilter = function(filterString) {
|
||||
// Match the start of the operation
|
||||
if(p < filterString.length) {
|
||||
operandRegExp.lastIndex = p;
|
||||
match = operandRegExp.exec(filterString);
|
||||
if(!match || match.index !== p) {
|
||||
throw $tw.language.getString("Error/FilterSyntax");
|
||||
}
|
||||
var operation = {
|
||||
prefix: "",
|
||||
operators: []
|
||||
};
|
||||
match = operandRegExp.exec(filterString);
|
||||
if(match && match.index === p) {
|
||||
if(match[1]) {
|
||||
// If there is a filter pragma
|
||||
operation.pragma = match[1];
|
||||
operation.suffix = match[2];
|
||||
p = match.index + match[0].length;
|
||||
} else if(match[3]) {
|
||||
// If there is a filter run prefix
|
||||
operation.prefix = match[3];
|
||||
p = p + operation.prefix.length;
|
||||
// Name for named prefixes
|
||||
if(match[4]) {
|
||||
operation.namedPrefix = match[4];
|
||||
}
|
||||
// Suffixes for filter run prefix
|
||||
if(match[5]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[5].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||
}
|
||||
});
|
||||
if(match[1]) {
|
||||
operation.prefix = match[1];
|
||||
p = p + operation.prefix.length;
|
||||
if(match[2]) {
|
||||
operation.namedPrefix = match[2];
|
||||
}
|
||||
if(match[3]) {
|
||||
operation.suffixes = [];
|
||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||
operation.suffixes.push([]);
|
||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||
entry = $tw.utils.trim(entry);
|
||||
if(entry) {
|
||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
// Opening square bracket
|
||||
if(match[6]) {
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
} else {
|
||||
// No filter run prefix
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
}
|
||||
// Quoted strings and unquoted title
|
||||
if(match[7] || match[8] || match[9]) { // Double quoted string, single quoted string or unquoted title
|
||||
if(match[4]) { // Opening square bracket
|
||||
p = parseFilterOperation(operation.operators,filterString,p);
|
||||
} else {
|
||||
p = match.index + match[0].length;
|
||||
}
|
||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||
operation.operators.push(
|
||||
{operator: "title", operands: [{text: match[7] || match[8] || match[9]}]}
|
||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||
);
|
||||
}
|
||||
results.push(operation);
|
||||
@@ -237,32 +211,23 @@ exports.getFilterRunPrefixes = function() {
|
||||
return this.filterRunPrefixes;
|
||||
}
|
||||
|
||||
exports.filterTiddlers = function(filterString,widget,source,options) {
|
||||
var fn = this.compileFilter(filterString,options);
|
||||
try {
|
||||
const fnResult = fn.call(this,source,widget);
|
||||
return fnResult;
|
||||
} catch(e) {
|
||||
return [`${$tw.language.getString("Error/Filter")}: ${e}`];
|
||||
}
|
||||
exports.filterTiddlers = function(filterString,widget,source) {
|
||||
var fn = this.compileFilter(filterString);
|
||||
return fn.call(this,source,widget);
|
||||
};
|
||||
|
||||
/*
|
||||
Compile a filter into a function with the signature fn(source,widget,options) where:
|
||||
Compile a filter into a function with the signature fn(source,widget) where:
|
||||
source: an iterator function for the source tiddlers, called source(iterator), where iterator is called as iterator(tiddler,title)
|
||||
widget: an optional widget node for retrieving the current tiddler etc.
|
||||
options: optional hashmap of options
|
||||
options.defaultFilterRunPrefix: the default filter run prefix to use when none is specified
|
||||
*/
|
||||
exports.compileFilter = function(filterString,options) {
|
||||
var defaultFilterRunPrefix = (options || {}).defaultFilterRunPrefix || "or";
|
||||
var cacheKey = filterString + "|" + defaultFilterRunPrefix;
|
||||
exports.compileFilter = function(filterString) {
|
||||
if(!this.filterCache) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
if(this.filterCache[cacheKey] !== undefined) {
|
||||
return this.filterCache[cacheKey];
|
||||
if(this.filterCache[filterString] !== undefined) {
|
||||
return this.filterCache[filterString];
|
||||
}
|
||||
var filterParseTree;
|
||||
try {
|
||||
@@ -283,11 +248,10 @@ exports.compileFilter = function(filterString,options) {
|
||||
// Create a function for the chain of operators in the operation
|
||||
var operationSubFunction = function(source,widget) {
|
||||
var accumulator = source,
|
||||
results = [];
|
||||
results = [],
|
||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
$tw.utils.each(operation.operators,function(operator) {
|
||||
var operands = [],
|
||||
multiValueOperands = [],
|
||||
isMultiValueOperand = [],
|
||||
operatorFunction;
|
||||
if(!operator.operator) {
|
||||
// Use the "title" operator if no operator is specified
|
||||
@@ -301,49 +265,29 @@ exports.compileFilter = function(filterString,options) {
|
||||
}
|
||||
$tw.utils.each(operator.operands,function(operand) {
|
||||
if(operand.indirect) {
|
||||
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||
operand.multiValue = [operand.value];
|
||||
} else if(operand.variable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||
operand.multiValue = [operand.value];
|
||||
} else if(operand.multiValuedVariable) {
|
||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||
var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source});
|
||||
if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) {
|
||||
operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || [];
|
||||
operand.value = operand.multiValue[0] || "";
|
||||
} else {
|
||||
operand.value = "";
|
||||
operand.multiValue = [];
|
||||
}
|
||||
operand.isMultiValueOperand = true;
|
||||
} else {
|
||||
operand.value = operand.text;
|
||||
operand.multiValue = [operand.value];
|
||||
}
|
||||
operands.push(operand.value);
|
||||
multiValueOperands.push(operand.multiValue);
|
||||
isMultiValueOperand.push(!!operand.isMultiValueOperand);
|
||||
});
|
||||
|
||||
// Invoke the appropriate filteroperator module
|
||||
results = operatorFunction(accumulator,{
|
||||
operator: operator.operator,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
multiValueOperands: multiValueOperands,
|
||||
isMultiValueOperand: isMultiValueOperand,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget,
|
||||
defaultFilterRunPrefix: defaultFilterRunPrefix
|
||||
});
|
||||
operator: operator.operator,
|
||||
operand: operands.length > 0 ? operands[0] : undefined,
|
||||
operands: operands,
|
||||
prefix: operator.prefix,
|
||||
suffix: operator.suffix,
|
||||
suffixes: operator.suffixes,
|
||||
regexp: operator.regexp
|
||||
},{
|
||||
wiki: self,
|
||||
widget: widget
|
||||
});
|
||||
if($tw.utils.isArray(results)) {
|
||||
accumulator = self.makeTiddlerIterator(results);
|
||||
} else {
|
||||
@@ -363,45 +307,27 @@ exports.compileFilter = function(filterString,options) {
|
||||
var filterRunPrefixes = self.getFilterRunPrefixes();
|
||||
// Wrap the operator functions in a wrapper function that depends on the prefix
|
||||
operationFunctions.push((function() {
|
||||
if(operation.pragma) {
|
||||
switch(operation.pragma) {
|
||||
case "defaultprefix":
|
||||
defaultFilterRunPrefix = operation.suffix || "or";
|
||||
break;
|
||||
default:
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // No prefix means that the operation is unioned into the result
|
||||
return filterRunPrefixes["or"](operationSubFunction, options);
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterPragma"));
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
return function(results,source,widget) {
|
||||
// Dummy response
|
||||
};
|
||||
} else {
|
||||
var options = {wiki: self, suffixes: operation.suffixes || []};
|
||||
switch(operation.prefix || "") {
|
||||
case "": // Use the default filter run prefix if none is specified
|
||||
return filterRunPrefixes[defaultFilterRunPrefix](operationSubFunction, options);
|
||||
case "=": // The results of the operation are pushed into the result without deduplication
|
||||
return filterRunPrefixes["all"](operationSubFunction, options);
|
||||
case "-": // The results of this operation are removed from the main result
|
||||
return filterRunPrefixes["except"](operationSubFunction, options);
|
||||
case "+": // This operation is applied to the main results so far
|
||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||
default:
|
||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||
} else {
|
||||
return function(results,source,widget) {
|
||||
results.clear();
|
||||
results.push($tw.language.getString("Error/FilterRunPrefix"));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})());
|
||||
});
|
||||
@@ -419,13 +345,7 @@ exports.compileFilter = function(filterString,options) {
|
||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||
var operationResult = operationFunction(results,source,widget);
|
||||
if(operationResult) {
|
||||
if(operationResult.variables) {
|
||||
// If the filter run prefix has returned variables, create a new fake widget with those variables
|
||||
widget = widget.makeFakeWidgetWithVariables(operationResult.variables);
|
||||
}
|
||||
}
|
||||
operationFunction(results,source,widget);
|
||||
});
|
||||
} else {
|
||||
results.push("/**-- Excessive filter recursion --**/");
|
||||
@@ -440,7 +360,7 @@ exports.compileFilter = function(filterString,options) {
|
||||
this.filterCache = Object.create(null);
|
||||
this.filterCacheCount = 0;
|
||||
}
|
||||
this.filterCache[cacheKey] = fnMeasured;
|
||||
this.filterCache[filterString] = fnMeasured;
|
||||
this.filterCacheCount++;
|
||||
return fnMeasured;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ module-type: filteroperator
|
||||
Filter operator for returning all the backtranscludes from a tiddler
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
@@ -18,3 +19,5 @@ exports.backtranscludes = function(source,operator,options) {
|
||||
});
|
||||
return results.makeTiddlerIterator(options.wiki);
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
@@ -13,9 +13,7 @@ Filter operator returning those input titles that pass a subfilter
|
||||
Export our filter function
|
||||
*/
|
||||
exports.filter = function(source,operator,options) {
|
||||
var suffixes = operator.suffixes || [],
|
||||
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or",
|
||||
filterFn = options.wiki.compileFilter(operator.operand,{defaultFilterRunPrefix}),
|
||||
var filterFn = options.wiki.compileFilter(operator.operand),
|
||||
results = [],
|
||||
target = operator.prefix !== "!";
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -16,8 +16,12 @@ exports.json = function(source,operand,options) {
|
||||
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,function(){return undefined;});
|
||||
|
||||
var data = $tw.utils.parseJSONSafe(title);
|
||||
try {
|
||||
data = JSON.parse(title);
|
||||
} catch(e) {
|
||||
data = undefined;
|
||||
}
|
||||
if(data !== undefined) {
|
||||
results.push(JSON.stringify(data,null,spaces));
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ exports.function = function(source,operator,options) {
|
||||
var functionName = operator.operands[0],
|
||||
params = [],
|
||||
results;
|
||||
$tw.utils.each(operator.multiValueOperands.slice(1),function(paramList) {
|
||||
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||
$tw.utils.each(operator.operands.slice(1),function(param) {
|
||||
params.push({value: param});
|
||||
});
|
||||
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
||||
|
||||
@@ -113,22 +113,6 @@ exports["jsonset"] = function(source,operator,options) {
|
||||
return results;
|
||||
};
|
||||
|
||||
exports["jsondelete"] = function(source,operator,options) {
|
||||
var indexes = operator.operands,
|
||||
results = [];
|
||||
source(function(tiddler,title) {
|
||||
var data = $tw.utils.parseJSONSafe(title,title);
|
||||
// If parsing failed (data equals original title and is a string), return unchanged
|
||||
if(data === title && typeof data === "string") {
|
||||
results.push(title);
|
||||
} else if(data) {
|
||||
data = deleteDataItem(data,indexes);
|
||||
results.push(JSON.stringify(data));
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||
*/
|
||||
@@ -160,7 +144,7 @@ function convertDataItemValueToStrings(item) {
|
||||
return ["null"]
|
||||
} else if(typeof item === "object") {
|
||||
var results = [],i,t;
|
||||
if(Array.isArray(item)) {
|
||||
if($tw.utils.isArray(item)) {
|
||||
// Return all the items in arrays recursively
|
||||
for(i=0; i<item.length; i++) {
|
||||
t = convertDataItemValueToStrings(item[i])
|
||||
@@ -194,7 +178,7 @@ function convertDataItemKeysToStrings(item) {
|
||||
return [];
|
||||
}
|
||||
var results = [];
|
||||
if(Array.isArray(item)) {
|
||||
if($tw.utils.isArray(item)) {
|
||||
for(var i=0; i<item.length; i++) {
|
||||
results.push(i.toString());
|
||||
}
|
||||
@@ -217,7 +201,7 @@ function getDataItemType(data,indexes) {
|
||||
return item;
|
||||
} else if(item === null) {
|
||||
return "null";
|
||||
} else if(Array.isArray(item)) {
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
return "array";
|
||||
} else if(typeof item === "object") {
|
||||
return "object";
|
||||
@@ -229,7 +213,7 @@ function getDataItemType(data,indexes) {
|
||||
function getItemAtIndex(item,index) {
|
||||
if($tw.utils.hop(item,index)) {
|
||||
return item[index];
|
||||
} else if(Array.isArray(item)) {
|
||||
} else if($tw.utils.isArray(item)) {
|
||||
index = $tw.utils.parseInt(index);
|
||||
if(index < 0) { index = index + item.length };
|
||||
return item[index]; // Will be undefined if index was out-of-bounds
|
||||
@@ -239,16 +223,15 @@ function getItemAtIndex(item,index) {
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
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 traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||
function getDataItem(data,indexes) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Get the item
|
||||
var item = data;
|
||||
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
|
||||
for(var i = 0; i < stopIndex; i++) {
|
||||
for(var i=0; i<indexes.length; i++) {
|
||||
if(item !== undefined) {
|
||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||
item = getItemAtIndex(item,indexes[i]);
|
||||
@@ -260,13 +243,6 @@ function traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||
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
|
||||
*/
|
||||
@@ -279,15 +255,18 @@ function setDataItem(data,indexes,value) {
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return value;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
// Traverse the JSON data structure using the index chain
|
||||
var current = data;
|
||||
for(var i = 0; i < indexes.length - 1; i++) {
|
||||
current = getItemAtIndex(current,indexes[i]);
|
||||
if(current === undefined) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
}
|
||||
// Add the value to the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current)) {
|
||||
if($tw.utils.isArray(current)) {
|
||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||
}
|
||||
@@ -297,32 +276,3 @@ function setDataItem(data,indexes,value) {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
|
||||
*/
|
||||
function deleteDataItem(data,indexes) {
|
||||
// Check for the root item - don't delete the root
|
||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||
return data;
|
||||
}
|
||||
// Traverse the JSON data structure using the index chain up to the parent
|
||||
var current = traverseIndexChain(data,indexes,true);
|
||||
if(current === undefined || current === null) {
|
||||
// Return the original JSON data structure if any of the index strings are invalid
|
||||
return data;
|
||||
}
|
||||
// Delete the item at the end of the index chain
|
||||
var lastIndex = indexes[indexes.length - 1];
|
||||
if(Array.isArray(current) && current !== null) {
|
||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||
// Check if index is valid before splicing
|
||||
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||
current.splice(lastIndex,1);
|
||||
}
|
||||
} else if(typeof current === "object" && current !== null) {
|
||||
delete current[lastIndex];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -217,10 +217,6 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||
source(function(tiddler,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) {
|
||||
return fnCalc(accumulator,currentValue);
|
||||
},initialValue);
|
||||
|
||||
@@ -14,31 +14,31 @@ Export our filter function
|
||||
*/
|
||||
exports.sort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,false,undefined,operator.operands[1]);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,false);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsort = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",false,true,undefined,operator.operands[1]);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",false,true);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortan = function(source, operator, options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results, operator.operands[0] || "title", operator.prefix === "!",false,false,true,operator.operands[1]);
|
||||
options.wiki.sortTiddlers(results, operator.operand || "title", operator.prefix === "!",false,false,true);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.sortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,false,undefined,operator.operands[1]);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,false);
|
||||
return results;
|
||||
};
|
||||
|
||||
exports.nsortcs = function(source,operator,options) {
|
||||
var results = prepare_results(source);
|
||||
options.wiki.sortTiddlers(results,operator.operands[0] || "title",operator.prefix === "!",true,true,undefined,operator.operands[1]);
|
||||
options.wiki.sortTiddlers(results,operator.operand || "title",operator.prefix === "!",true,true);
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,14 +37,14 @@ exports.trim = function(source,operator,options) {
|
||||
operand = (operator.operand || ""),
|
||||
fnCalc;
|
||||
if(suffix === "prefix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];};
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimPrefix(a,b)];}
|
||||
} else if(suffix === "suffix") {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];};
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix(a,b)];}
|
||||
} else {
|
||||
if(operand === "") {
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];};
|
||||
fnCalc = function(a) {return [$tw.utils.trim(a)];}
|
||||
} else {
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];};
|
||||
fnCalc = function(a,b) {return [$tw.utils.trimSuffix($tw.utils.trimPrefix(a,b),b)];}
|
||||
}
|
||||
}
|
||||
source(function(tiddler,title) {
|
||||
@@ -71,53 +71,107 @@ exports.join = makeStringReducingOperator(
|
||||
},null
|
||||
);
|
||||
|
||||
const dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
var dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
||||
|
||||
exports.levenshtein = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
const diffs = dmp.diffMain(a,b);
|
||||
return [dmp.diffLevenshtein(diffs).toString()];
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
diffs = dmpObject.diff_main(a,b);
|
||||
return [dmpObject.diff_levenshtein(diffs) + ""];
|
||||
}
|
||||
);
|
||||
|
||||
// this function is adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
// these two functions are adapted from https://github.com/google/diff-match-patch/wiki/Line-or-Word-Diffs
|
||||
function diffLineWordMode(text1,text2,mode) {
|
||||
var a = $tw.utils.diffPartsToChars(text1,text2,mode);
|
||||
var dmpObject = new dmp.diff_match_patch();
|
||||
var a = diffPartsToChars(text1,text2,mode);
|
||||
var lineText1 = a.chars1;
|
||||
var lineText2 = a.chars2;
|
||||
var lineArray = a.lineArray;
|
||||
var diffs = dmp.diffMain(lineText1,lineText2,false);
|
||||
dmp.diffCharsToLines(diffs,lineArray);
|
||||
var diffs = dmpObject.diff_main(lineText1,lineText2,false);
|
||||
dmpObject.diff_charsToLines_(diffs,lineArray);
|
||||
return diffs;
|
||||
}
|
||||
|
||||
function diffPartsToChars(text1,text2,mode) {
|
||||
var lineArray = [];
|
||||
var lineHash = {};
|
||||
lineArray[0] = '';
|
||||
|
||||
function diff_linesToPartsMunge_(text,mode) {
|
||||
var chars = '';
|
||||
var lineStart = 0;
|
||||
var lineEnd = -1;
|
||||
var lineArrayLength = lineArray.length,
|
||||
regexpResult;
|
||||
var searchRegexp = /\W+/g;
|
||||
while(lineEnd < text.length - 1) {
|
||||
if(mode === "words") {
|
||||
regexpResult = searchRegexp.exec(text);
|
||||
lineEnd = searchRegexp.lastIndex;
|
||||
if(regexpResult === null) {
|
||||
lineEnd = text.length;
|
||||
}
|
||||
lineEnd = --lineEnd;
|
||||
} else {
|
||||
lineEnd = text.indexOf('\n', lineStart);
|
||||
if(lineEnd == -1) {
|
||||
lineEnd = text.length - 1;
|
||||
}
|
||||
}
|
||||
var line = text.substring(lineStart, lineEnd + 1);
|
||||
|
||||
if(lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : (lineHash[line] !== undefined)) {
|
||||
chars += String.fromCharCode(lineHash[line]);
|
||||
} else {
|
||||
if(lineArrayLength == maxLines) {
|
||||
line = text.substring(lineStart);
|
||||
lineEnd = text.length;
|
||||
}
|
||||
chars += String.fromCharCode(lineArrayLength);
|
||||
lineHash[line] = lineArrayLength;
|
||||
lineArray[lineArrayLength++] = line;
|
||||
}
|
||||
lineStart = lineEnd + 1;
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
var maxLines = 40000;
|
||||
var chars1 = diff_linesToPartsMunge_(text1,mode);
|
||||
maxLines = 65535;
|
||||
var chars2 = diff_linesToPartsMunge_(text2,mode);
|
||||
return {chars1: chars1, chars2: chars2, lineArray: lineArray};
|
||||
};
|
||||
|
||||
exports.makepatches = function(source,operator,options) {
|
||||
var suffix = operator.suffix || "",
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
suffix = operator.suffix || "",
|
||||
result = [];
|
||||
|
||||
source(function(tiddler,title) {
|
||||
let diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmp.patchMake(title,diffs);
|
||||
} else {
|
||||
patches = dmp.patchMake(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmp.patchToText(patches)]);
|
||||
});
|
||||
source(function(tiddler,title) {
|
||||
var diffs, patches;
|
||||
if(suffix === "lines" || suffix === "words") {
|
||||
diffs = diffLineWordMode(title,operator.operand,suffix);
|
||||
patches = dmpObject.patch_make(title,diffs);
|
||||
} else {
|
||||
patches = dmpObject.patch_make(title,operator.operand);
|
||||
}
|
||||
Array.prototype.push.apply(result,[dmpObject.patch_toText(patches)]);
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.applypatches = makeStringBinaryOperator(
|
||||
function(a,b) {
|
||||
let patches;
|
||||
var dmpObject = new dmp.diff_match_patch(),
|
||||
patches;
|
||||
try {
|
||||
patches = dmp.patchFromText(b);
|
||||
patches = dmpObject.patch_fromText(b);
|
||||
} catch(e) {
|
||||
}
|
||||
if(patches) {
|
||||
return [dmp.patchApply(patches,a)[0]];
|
||||
return [dmpObject.patch_apply(patches,a)[0]];
|
||||
} else {
|
||||
return [a];
|
||||
}
|
||||
@@ -225,7 +279,7 @@ exports.pad = function(source,operator,options) {
|
||||
}
|
||||
});
|
||||
return results;
|
||||
};
|
||||
}
|
||||
|
||||
exports.charcode = function(source,operator,options) {
|
||||
var chars = [];
|
||||
|
||||
@@ -13,9 +13,7 @@ Filter operator returning its operand evaluated as a filter
|
||||
Export our filter function
|
||||
*/
|
||||
exports.subfilter = function(source,operator,options) {
|
||||
var suffixes = operator.suffixes || [],
|
||||
defaultFilterRunPrefix = (suffixes[0] || [options.defaultFilterRunPrefix] || [])[0] || "or";
|
||||
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source,{defaultFilterRunPrefix});
|
||||
var list = options.wiki.filterTiddlers(operator.operand,options.widget,source);
|
||||
if(operator.prefix === "!") {
|
||||
var results = [];
|
||||
source(function(tiddler,title) {
|
||||
|
||||
@@ -16,13 +16,12 @@ exports.title = function(source,operator,options) {
|
||||
var results = [];
|
||||
if(operator.prefix === "!") {
|
||||
source(function(tiddler,title) {
|
||||
var titleList = operator.multiValueOperands[0] || [];
|
||||
if(tiddler && titleList.indexOf(tiddler.fields.title) === -1) {
|
||||
if(tiddler && tiddler.fields.title !== operator.operand) {
|
||||
results.push(title);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Array.prototype.push.apply(results,operator.multiValueOperands[0]);
|
||||
results.push(operator.operand);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user