mirror of
https://github.com/Jermolene/TiddlyWiki5.git
synced 2025-12-06 02:30:46 -08:00
Merge branch 'master' into dynamic-macro-calls
This commit is contained in:
commit
ad4c1ca5a1
1283 changed files with 20288 additions and 6905 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -10,7 +10,7 @@ jobs:
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
|
|
@ -30,7 +30,7 @@ jobs:
|
||||||
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
TW5_BUILD_MAIN_EDITION: "./editions/prerelease"
|
||||||
TW5_BUILD_OUTPUT: "./output/prerelease"
|
TW5_BUILD_OUTPUT: "./output/prerelease"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
|
|
@ -62,7 +62,7 @@ jobs:
|
||||||
TW5_BUILD_OUTPUT: "./output"
|
TW5_BUILD_OUTPUT: "./output"
|
||||||
TW5_BUILD_ARCHIVE: "./output"
|
TW5_BUILD_ARCHIVE: "./output"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: "${{ env.NODE_VERSION }}"
|
node-version: "${{ env.NODE_VERSION }}"
|
||||||
|
|
|
||||||
40
.github/workflows/eslint.yml
vendored
Normal file
40
.github/workflows/eslint.yml
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
name: ESLint
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: lint-${{ github.event.pull_request.number || github.ref_name }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
# Needed for GitHub Checks API
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
eslint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install --include=dev
|
||||||
|
|
||||||
|
- name: Run ESLint with reviewdog (GitHub Checks)
|
||||||
|
uses: reviewdog/action-eslint@v1
|
||||||
|
with:
|
||||||
|
eslint_flags: '.'
|
||||||
|
reporter: github-pr-check
|
||||||
|
fail_level: error
|
||||||
|
level: error
|
||||||
|
tool_name: ESLint PR code
|
||||||
9
.github/workflows/pr-check-build-size.yml
vendored
9
.github/workflows/pr-check-build-size.yml
vendored
|
|
@ -2,6 +2,11 @@ name: Calculate PR build size
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [opened, reopened, synchronize]
|
types: [opened, reopened, synchronize]
|
||||||
|
paths:
|
||||||
|
- 'boot/**'
|
||||||
|
- 'core/**'
|
||||||
|
- 'themes/tiddlywiki/snowwhite/**'
|
||||||
|
- 'themes/tiddlywiki/vanilla/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
calculate-build-size:
|
calculate-build-size:
|
||||||
|
|
@ -15,11 +20,11 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: build-size-check
|
- name: build-size-check
|
||||||
id: get_sizes
|
id: get_sizes
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ github.event.pull_request.number }}
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
repo: ${{ github.repository }}
|
repo: ${{ github.repository }}
|
||||||
base_ref: ${{ github.base_ref }}
|
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
mode: size:calc
|
mode: size:calc
|
||||||
|
|
||||||
|
|
|
||||||
2
.github/workflows/pr-comment-build-size.yml
vendored
2
.github/workflows/pr-comment-build-size.yml
vendored
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Build and check size
|
- name: Build and check size
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
with:
|
with:
|
||||||
pr_number: ${{ inputs.pr_number }}
|
pr_number: ${{ inputs.pr_number }}
|
||||||
repo: ${{ github.repository }}
|
repo: ${{ github.repository }}
|
||||||
|
|
|
||||||
18
.github/workflows/pr-path-validation.yml
vendored
18
.github/workflows/pr-path-validation.yml
vendored
|
|
@ -1,18 +0,0 @@
|
||||||
name: Validate PR Paths
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, reopened, synchronize]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
validate-pr:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Validate PR
|
|
||||||
uses: TiddlyWiki/cerebrus@v4
|
|
||||||
with:
|
|
||||||
pr_number: ${{ github.event.pull_request.number }}
|
|
||||||
repo: ${{ github.repository }}
|
|
||||||
base_ref: ${{ github.base_ref }}
|
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
37
.github/workflows/pr-validation.yml
vendored
Normal file
37
.github/workflows/pr-validation.yml
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
name: PR Validation
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, reopened, synchronize]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
jobs:
|
||||||
|
validate-pr:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Step 1: Validate PR paths
|
||||||
|
- name: Validate PR Paths
|
||||||
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
|
with:
|
||||||
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
|
repo: ${{ github.repository }}
|
||||||
|
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
mode: rules
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Step 2: Validate change notes
|
||||||
|
- name: Validate Change Notes
|
||||||
|
uses: TiddlyWiki/cerebrus@v6
|
||||||
|
with:
|
||||||
|
pr_number: ${{ github.event.pull_request.number }}
|
||||||
|
repo: ${{ github.repository }}
|
||||||
|
base_ref: ${{ github.event.pull_request.base.ref }}
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
mode: changenotes
|
||||||
|
continue-on-error: false
|
||||||
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
# Default to the current version number for building the plugin library
|
# Default to the current version number for building the plugin library
|
||||||
|
|
||||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||||
TW5_BUILD_VERSION=v5.3.7
|
TW5_BUILD_VERSION=v5.4.0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||||
|
|
@ -73,10 +73,8 @@ rm $TW5_BUILD_OUTPUT/dev/static/*
|
||||||
|
|
||||||
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
echo "<a href='./plugins/tiddlywiki/tw2parser/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tw2parser/index.html</a>" > $TW5_BUILD_OUTPUT/classicparserdemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
echo "<a href='./plugins/tiddlywiki/codemirror/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/codemirror/index.html</a>" > $TW5_BUILD_OUTPUT/codemirrordemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/d3/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/d3/index.html</a>" > $TW5_BUILD_OUTPUT/d3demo.html
|
|
||||||
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
echo "<a href='./plugins/tiddlywiki/highlight/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/highlight/index.html</a>" > $TW5_BUILD_OUTPUT/highlightdemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
echo "<a href='./plugins/tiddlywiki/markdown/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/markdown/index.html</a>" > $TW5_BUILD_OUTPUT/markdowndemo.html
|
||||||
echo "<a href='./plugins/tiddlywiki/tahoelafs/index.html'>Moved to http://tiddlywiki.com/plugins/tiddlywiki/tahoelafs/index.html</a>" > $TW5_BUILD_OUTPUT/tahoelafs.html
|
|
||||||
|
|
||||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||||
|
|
||||||
|
|
@ -159,6 +157,13 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||||
--rendertiddler $:/core/save/all-external-js tour.html text/plain \
|
--rendertiddler $:/core/save/all-external-js tour.html text/plain \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
|
# /surveys.html surveys edition
|
||||||
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
|
./editions/tiddlywiki-surveys \
|
||||||
|
--output $TW5_BUILD_OUTPUT \
|
||||||
|
--build index \
|
||||||
|
|| exit 1
|
||||||
|
|
||||||
# /share.html Custom edition for sharing via the URL
|
# /share.html Custom edition for sharing via the URL
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
./editions/share \
|
./editions/share \
|
||||||
|
|
@ -294,26 +299,6 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
--rendertiddler $:/core/save/empty plugins/tiddlywiki/katex/empty.html text/plain \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
# /plugins/tiddlywiki/tahoelafs/index.html Demo wiki with Tahoe-LAFS plugin
|
|
||||||
# /plugins/tiddlywiki/tahoelafs/empty.html Empty wiki with Tahoe-LAFS plugin
|
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
|
||||||
./editions/tahoelafs \
|
|
||||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
|
||||||
--output $TW5_BUILD_OUTPUT \
|
|
||||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/tahoelafs/index.html text/plain \
|
|
||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/tahoelafs/empty.html text/plain \
|
|
||||||
|| exit 1
|
|
||||||
|
|
||||||
# /plugins/tiddlywiki/d3/index.html Demo wiki with D3 plugin
|
|
||||||
# /plugins/tiddlywiki/d3/empty.html Empty wiki with D3 plugin
|
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
|
||||||
./editions/d3demo \
|
|
||||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
|
||||||
--output $TW5_BUILD_OUTPUT \
|
|
||||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/d3/index.html text/plain \
|
|
||||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/d3/empty.html text/plain \
|
|
||||||
|| exit 1
|
|
||||||
|
|
||||||
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
# /plugins/tiddlywiki/codemirror/index.html Demo wiki with codemirror plugin
|
||||||
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
# /plugins/tiddlywiki/codemirror/empty.html Empty wiki with codemirror plugin
|
||||||
node $TW5_BUILD_TIDDLYWIKI \
|
node $TW5_BUILD_TIDDLYWIKI \
|
||||||
|
|
|
||||||
69
boot/boot.js
69
boot/boot.js
|
|
@ -641,7 +641,7 @@ $tw.utils.evalGlobal = function(code,context,filename,sandbox,allowGlobals) {
|
||||||
// Call the function and return the exports
|
// Call the function and return the exports
|
||||||
return fn.apply(null,contextValues);
|
return fn.apply(null,contextValues);
|
||||||
};
|
};
|
||||||
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
$tw.utils.sandbox = !$tw.browser ? vm.createContext({}) : undefined;
|
||||||
/*
|
/*
|
||||||
Run code in a sandbox with only the specified context variables in scope
|
Run code in a sandbox with only the specified context variables in scope
|
||||||
*/
|
*/
|
||||||
|
|
@ -799,12 +799,13 @@ the password, and to encrypt/decrypt a block of text
|
||||||
$tw.utils.Crypto = function() {
|
$tw.utils.Crypto = function() {
|
||||||
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
var sjcl = $tw.node ? (global.sjcl || require("./sjcl.js")) : window.sjcl,
|
||||||
currentPassword = null,
|
currentPassword = null,
|
||||||
callSjcl = function(method,inputText,password) {
|
callSjcl = function(method,inputText,password,options) {
|
||||||
|
options = options || {};
|
||||||
password = password || currentPassword;
|
password = password || currentPassword;
|
||||||
var outputText;
|
var outputText;
|
||||||
try {
|
try {
|
||||||
if(password) {
|
if(password) {
|
||||||
outputText = sjcl[method](password,inputText);
|
outputText = sjcl[method](password,inputText,options);
|
||||||
}
|
}
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
console.log("Crypto error:" + ex);
|
console.log("Crypto error:" + ex);
|
||||||
|
|
@ -830,7 +831,8 @@ $tw.utils.Crypto = function() {
|
||||||
return !!currentPassword;
|
return !!currentPassword;
|
||||||
}
|
}
|
||||||
this.encrypt = function(text,password) {
|
this.encrypt = function(text,password) {
|
||||||
return callSjcl("encrypt",text,password);
|
// set default ks:256 -- see: http://bitwiseshiftleft.github.io/sjcl/doc/convenience.js.html
|
||||||
|
return callSjcl("encrypt",text,password,{v:1,iter:10000,ks:256,ts:64,mode:"ccm",adata:"",cipher:"aes"});
|
||||||
};
|
};
|
||||||
this.decrypt = function(text,password) {
|
this.decrypt = function(text,password) {
|
||||||
return callSjcl("decrypt",text,password);
|
return callSjcl("decrypt",text,password);
|
||||||
|
|
@ -1433,7 +1435,7 @@ $tw.Wiki = function(options) {
|
||||||
checkTiddler = function(tiddler,title) {
|
checkTiddler = function(tiddler,title) {
|
||||||
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
if(tiddler && tiddler.fields.type === "application/json" && tiddler.fields["plugin-type"] && (!pluginType || tiddler.fields["plugin-type"] === pluginType)) {
|
||||||
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
var disablingTiddler = self.getTiddler("$:/config/Plugins/Disabled/" + title);
|
||||||
if(title === "$:/core" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
if(title === "$:/core" || title === "$:/core-server" || !disablingTiddler || (disablingTiddler.fields.text || "").trim() !== "yes") {
|
||||||
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
self.unregisterPluginTiddlers(null,[title]); // Unregister the plugin if it's already registered
|
||||||
pluginTiddlers.push(tiddler);
|
pluginTiddlers.push(tiddler);
|
||||||
registeredTitles.push(tiddler.fields.title);
|
registeredTitles.push(tiddler.fields.title);
|
||||||
|
|
@ -1530,7 +1532,8 @@ Define all modules stored in ordinary tiddlers
|
||||||
*/
|
*/
|
||||||
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
$tw.Wiki.prototype.defineTiddlerModules = function() {
|
||||||
this.each(function(tiddler,title) {
|
this.each(function(tiddler,title) {
|
||||||
if(tiddler.hasField("module-type")) {
|
// Modules in draft tiddlers are disabled
|
||||||
|
if(tiddler.hasField("module-type") && (!tiddler.hasField("draft.of"))) {
|
||||||
switch(tiddler.fields.type) {
|
switch(tiddler.fields.type) {
|
||||||
case "application/javascript":
|
case "application/javascript":
|
||||||
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
// We only define modules that haven't already been defined, because in the browser modules in system tiddlers are defined in inline script
|
||||||
|
|
@ -1557,6 +1560,11 @@ $tw.Wiki.prototype.defineShadowModules = function() {
|
||||||
this.eachShadow(function(tiddler,title) {
|
this.eachShadow(function(tiddler,title) {
|
||||||
// Don't define the module if it is overidden by an ordinary tiddler
|
// Don't define the module if it is overidden by an ordinary tiddler
|
||||||
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
if(!self.tiddlerExists(title) && tiddler.hasField("module-type")) {
|
||||||
|
if(tiddler.hasField("draft.of")) {
|
||||||
|
// Report a fundamental problem
|
||||||
|
console.warn(`TiddlyWiki: Plugins should not contain tiddlers with a 'draft.of' field: ${tiddler.fields.title}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Define the module
|
// Define the module
|
||||||
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
$tw.modules.define(tiddler.fields.title,tiddler.fields["module-type"],tiddler.fields.text);
|
||||||
}
|
}
|
||||||
|
|
@ -1905,7 +1913,7 @@ $tw.loadTiddlersFromFile = function(filepath,fields) {
|
||||||
fileSize = fs.statSync(filepath).size,
|
fileSize = fs.statSync(filepath).size,
|
||||||
data;
|
data;
|
||||||
if(fileSize > $tw.config.maxEditFileSize) {
|
if(fileSize > $tw.config.maxEditFileSize) {
|
||||||
data = "File " + filepath + "not loaded because it is too large";
|
data = "File " + filepath + " not loaded because it is too large";
|
||||||
console.log("Warning: " + data);
|
console.log("Warning: " + data);
|
||||||
ext = ".txt";
|
ext = ".txt";
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1976,22 +1984,41 @@ filepath: pathname of the directory containing the specification file
|
||||||
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
$tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||||
var tiddlers = [];
|
var tiddlers = [];
|
||||||
// Read the specification
|
// Read the specification
|
||||||
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"));
|
var filesInfo = $tw.utils.parseJSONSafe(fs.readFileSync(filepath + path.sep + "tiddlywiki.files","utf8"), function(e) {
|
||||||
|
console.log("Warning: tiddlywiki.files in " + filepath + " invalid: " + e.message);
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
// Helper to process a file
|
// Helper to process a file
|
||||||
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
var processFile = function(filename,isTiddlerFile,fields,isEditableFile,rootPath) {
|
||||||
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
var extInfo = $tw.config.fileExtensionInfo[path.extname(filename)],
|
||||||
type = (extInfo || {}).type || fields.type || "text/plain",
|
type = (extInfo || {}).type || fields.type || "text/plain",
|
||||||
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
typeInfo = $tw.config.contentTypeInfo[type] || {},
|
||||||
pathname = path.resolve(filepath,filename),
|
pathname = path.resolve(filepath,filename),
|
||||||
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8"),
|
|
||||||
metadata = $tw.loadMetadataForFile(pathname) || {},
|
metadata = $tw.loadMetadataForFile(pathname) || {},
|
||||||
fileTiddlers;
|
fileTooLarge = false,
|
||||||
|
text, fileTiddlers;
|
||||||
|
|
||||||
|
if("_canonical_uri" in fields) {
|
||||||
|
text = "";
|
||||||
|
} else if(fs.statSync(pathname).size > $tw.config.maxEditFileSize) {
|
||||||
|
var msg = "File " + pathname + " not loaded because it is too large";
|
||||||
|
console.log("Warning: " + msg);
|
||||||
|
fileTooLarge = true;
|
||||||
|
text = isTiddlerFile ? msg : "";
|
||||||
|
} else {
|
||||||
|
text = fs.readFileSync(pathname,typeInfo.encoding || "utf8");
|
||||||
|
}
|
||||||
|
|
||||||
if(isTiddlerFile) {
|
if(isTiddlerFile) {
|
||||||
fileTiddlers = $tw.wiki.deserializeTiddlers(path.extname(pathname),text,metadata) || [];
|
fileTiddlers = $tw.wiki.deserializeTiddlers(fileTooLarge ? ".txt" : path.extname(pathname),text,metadata) || [];
|
||||||
} else {
|
} else {
|
||||||
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
fileTiddlers = [$tw.utils.extend({text: text},metadata)];
|
||||||
}
|
}
|
||||||
var combinedFields = $tw.utils.extend({},fields,metadata);
|
var combinedFields = $tw.utils.extend({},fields,metadata);
|
||||||
|
if(fileTooLarge && isTiddlerFile) {
|
||||||
|
delete combinedFields.type; // type altered
|
||||||
|
}
|
||||||
$tw.utils.each(fileTiddlers,function(tiddler) {
|
$tw.utils.each(fileTiddlers,function(tiddler) {
|
||||||
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
$tw.utils.each(combinedFields,function(fieldInfo,name) {
|
||||||
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
if(typeof fieldInfo === "string" || $tw.utils.isArray(fieldInfo)) {
|
||||||
|
|
@ -2066,6 +2093,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||||
} else if(tidInfo.suffix) {
|
} else if(tidInfo.suffix) {
|
||||||
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
tidInfo.fields.text = {suffix: tidInfo.suffix};
|
||||||
}
|
}
|
||||||
|
tidInfo.fields = tidInfo.fields || {};
|
||||||
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
processFile(tidInfo.file,tidInfo.isTiddlerFile,tidInfo.fields);
|
||||||
});
|
});
|
||||||
// Process any listed directories
|
// Process any listed directories
|
||||||
|
|
@ -2087,6 +2115,7 @@ $tw.loadTiddlersFromSpecification = function(filepath,excludeRegExp) {
|
||||||
var thisPath = path.relative(filepath, files[t]),
|
var thisPath = path.relative(filepath, files[t]),
|
||||||
filename = path.basename(thisPath);
|
filename = path.basename(thisPath);
|
||||||
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
if(filename !== "tiddlywiki.files" && !metaRegExp.test(filename) && fileRegExp.test(filename)) {
|
||||||
|
dirSpec.fields = dirSpec.fields || {};
|
||||||
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
processFile(thisPath,dirSpec.isTiddlerFile,dirSpec.fields,dirSpec.isEditableFile,dirSpec.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2350,6 +2379,7 @@ $tw.loadTiddlersNode = function() {
|
||||||
});
|
});
|
||||||
// Load the core tiddlers
|
// Load the core tiddlers
|
||||||
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.corePath));
|
||||||
|
$tw.wiki.addTiddler($tw.loadPluginFolder($tw.boot.coreServerPath));
|
||||||
// Load any extra plugins
|
// Load any extra plugins
|
||||||
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
$tw.utils.each($tw.boot.extraPlugins,function(name) {
|
||||||
if(name.charAt(0) === "+") { // Relative path to plugin
|
if(name.charAt(0) === "+") { // Relative path to plugin
|
||||||
|
|
@ -2423,6 +2453,7 @@ $tw.boot.initStartup = function(options) {
|
||||||
// System paths and filenames
|
// System paths and filenames
|
||||||
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
$tw.boot.bootPath = options.bootPath || path.dirname(module.filename);
|
||||||
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
$tw.boot.corePath = path.resolve($tw.boot.bootPath,"../core");
|
||||||
|
$tw.boot.coreServerPath = path.resolve($tw.boot.bootPath,"../core-server");
|
||||||
// If there's no arguments then default to `--help`
|
// If there's no arguments then default to `--help`
|
||||||
if($tw.boot.argv.length === 0) {
|
if($tw.boot.argv.length === 0) {
|
||||||
$tw.boot.argv = ["--help"];
|
$tw.boot.argv = ["--help"];
|
||||||
|
|
@ -2547,10 +2578,10 @@ $tw.boot.execStartup = function(options){
|
||||||
if($tw.safeMode) {
|
if($tw.safeMode) {
|
||||||
$tw.wiki.processSafeMode();
|
$tw.wiki.processSafeMode();
|
||||||
}
|
}
|
||||||
// Register typed modules from the tiddlers we've just loaded
|
// Register typed modules from the tiddlers we've just loaded and any modules within plugins
|
||||||
$tw.wiki.defineTiddlerModules();
|
// Tiddlers should appear last so that they may overwrite shadows during module registration
|
||||||
// And any modules within plugins
|
|
||||||
$tw.wiki.defineShadowModules();
|
$tw.wiki.defineShadowModules();
|
||||||
|
$tw.wiki.defineTiddlerModules();
|
||||||
// Make sure the crypto state tiddler is up to date
|
// Make sure the crypto state tiddler is up to date
|
||||||
if($tw.crypto) {
|
if($tw.crypto) {
|
||||||
$tw.crypto.updateCryptoStateTiddler();
|
$tw.crypto.updateCryptoStateTiddler();
|
||||||
|
|
@ -2619,11 +2650,13 @@ $tw.boot.executeNextStartupTask = function(callback) {
|
||||||
$tw.boot.log(s.join(" "));
|
$tw.boot.log(s.join(" "));
|
||||||
// Execute task
|
// Execute task
|
||||||
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
if(!$tw.utils.hop(task,"synchronous") || task.synchronous) {
|
||||||
task.startup();
|
const thenable = task.startup();
|
||||||
if(task.name) {
|
if(thenable && typeof thenable.then === "function"){
|
||||||
$tw.boot.executedStartupModules[task.name] = true;
|
thenable.then(asyncTaskCallback);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return asyncTaskCallback();
|
||||||
}
|
}
|
||||||
return $tw.boot.executeNextStartupTask(callback);
|
|
||||||
} else {
|
} else {
|
||||||
task.startup(asyncTaskCallback);
|
task.startup(asyncTaskCallback);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
5
community/docs/Community Cards Caveats.tid
Normal file
5
community/docs/Community Cards Caveats.tid
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
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.''
|
||||||
11
community/docs/Community Cards.tid
Normal file
11
community/docs/Community Cards.tid
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
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]]
|
||||||
26
community/docs/Displaying Community Cards.tid
Normal file
26
community/docs/Displaying Community Cards.tid
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
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">>
|
||||||
36
community/docs/Submitting a Community Card.tid
Normal file
36
community/docs/Submitting a Community Card.tid
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
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
|
||||||
10
community/people/Arlen22.tid
Normal file
10
community/people/Arlen22.tid
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
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.
|
||||||
29
community/people/EricShulman.tid
Normal file
29
community/people/EricShulman.tid
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
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.
|
||||||
21
community/people/Jermolene.tid
Normal file
21
community/people/Jermolene.tid
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
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]].
|
||||||
19
community/people/LinOnetwo.tid
Normal file
19
community/people/LinOnetwo.tid
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
avatar: /9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgICAgJCAkKCgkNDgwODRMREBARExwUFhQWFBwrGx8bGx8bKyYuJSMlLiZENS8vNUROQj5CTl9VVV93cXecnNEBCAgICAkICQoKCQ0ODA4NExEQEBETHBQWFBYUHCsbHxsbHxsrJi4lIyUuJkQ1Ly81RE5CPkJOX1VVX3dxd5yc0f/CABEIACAAIAMBIgACEQEDEQH/xAAuAAEAAwEBAAAAAAAAAAAAAAAGAwQHAgUBAAMBAAAAAAAAAAAAAAAAAAACAwT/2gAMAwEAAhADEAAAAOfCWAMdKKetM4wOvY5OcvZnrYf/xAApEAACAQQBBAECBwAAAAAAAAABAgMABAURQQYSIVETFCIxMkJicYKh/9oACAEBAAE/AEtysaStr7mPaPeuazWdMM4gEnfPryW8hBUuZvou2RXRxyreBWPmgyNqs8f8MOQalhdY7Vz+R4/s/qfP+1edNi/zl7HDcFbmS3E8CcMR4INP0PkBhklIm+sZNtFtQiV0nj57Owl+dSrSTFgD6/CtH4VV9lU3oAbPngAVY389lc5URuUZkMxhnR4pvW0VwDqsP1FNmLWYqCpikMbngmliJNY+aKzyTxXS6lRAyg/u5rq+5x2RsuyTa3MQMlvKniRGThTUd1JYXUdzAwDvqVxGdRXMbfrVOD7HBrG3mNEsU8z98TRhl9eRzX//xAAcEQACAgIDAAAAAAAAAAAAAAABAgARAzESIVH/2gAIAQIBAT8ARuXZPsul3Eoje5lBQWBP/8QAGREAAwEBAQAAAAAAAAAAAAAAAAECEiER/9oACAEDAQE/AM98Lk7LJe20z//Z
|
||||||
|
created: 20251110102157310
|
||||||
|
first-sighting: 2019-03-01
|
||||||
|
fullname: Lin Onetwo
|
||||||
|
github: linonetwo
|
||||||
|
homepage: https://wiki.onetwo.website/
|
||||||
|
modified: 20251111184556193
|
||||||
|
tags: Community/Person Community/Team/Contributors
|
||||||
|
talk.tiddlywiki.org: linonetwo
|
||||||
|
title: @linonetwo
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
|
||||||
|
Since 2014, when I started college, I've been on a quest for a lifelong PKM tool. I cherish my life and all my experiences, and I don’t want to forget any of them. When I’m deeply focused on a task, it’s easy to lose sight of other important parts of my life—so I needed a system to help me stay balanced.
|
||||||
|
|
||||||
|
Early on, I tried TiddlyWiki several times, but I was initially put off by its save mechanism and markup editing. That changed when I discovered an auto-backup script, which gave me the confidence to fully commit. Over time, I improved the script and eventually transitioned to using TidGi-Desktop and TidGi-Mobile.
|
||||||
|
|
||||||
|
Today, my TiddlyWiki holds all my game design ideas and progress logs—it has truly become my second brain. With the help of LLM-powered programming tools, I’ve enhanced it with numerous plugins, allowing me to manage my mind in a more programmable and structured way. As a game developer, TiddlyWiki isn't the core of my professional work; But I've invested so much time because it's fundamentally about upgrading my mind.
|
||||||
|
|
||||||
|
Most of my notes are open by default and shared publicly on my homepage as a digital garden.
|
||||||
11
community/people/MotovunJack.tid
Normal file
11
community/people/MotovunJack.tid
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
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.
|
||||||
25
community/people/PMario.tid
Normal file
25
community/people/PMario.tid
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
avatar: UklGRiwIAABXRUJQVlA4WAoAAAAwAAAAPwAAPwAASUNDUCACAAAAAAIgbGNtcwRAAABtbnRyR1JBWVhZWiAH6QALAAoACwADAAZhY3NwTVNGVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZkZXNjAAAAzAAAAG5jcHJ0AAABPAAAADZ3dHB0AAABdAAAABRrVFJDAAABiAAAACBkbW5kAAABqAAAACRkbWRkAAABzAAAAFJtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFIAAAAcAEcASQBNAFAAIABiAHUAaQBsAHQALQBpAG4AIABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAbWx1YwAAAAAAAAABAAAADGVuVVMAAAAaAAAAHABQAHUAYgBsAGkAYwAgAEQAbwBtAGEAaQBuAABYWVogAAAAAAAA81EAAQAAAAEWzHBhcmEAAAAAAAMAAAACZmYAAPKnAAANWQAAE9AAAApbbWx1YwAAAAAAAAABAAAADGVuVVMAAAAIAAAAHABHAEkATQBQbWx1YwAAAAAAAAABAAAADGVuVVMAAAA2AAAAHABEADYANQAgAEcAcgBhAHkAcwBjAGEAbABlACAAdwBpAHQAaAAgAHMAUgBHAEIAIABUAFIAQwAAVlA4TOYFAAAvP8APEDWGgbRtWv+yt/0WImICOBvWn1C4dFi1bStbvpY8Qg2ePANNNAMh3N2db/7A91/7CHBvBBRr25ZFH+4k98ihkqi2CP4tsANvX8a+8y8Ct04dn0nuUt39ZiBJkowqt911M+MJ1G3bNiZJr1iP0DZ+2bbdadsqprOjAqmoUIX9hf3Fl5/uPYV7I3OMeoFzIvrvwG0kRUr3zPLdYMMXaqrMMsp0K4fufKO6c2hFV5Zh7kRROZX0PSCmB/3KWQwpuiekWelSRZDW94d0q750NrxavpFn1eLNQ9EV8nWlmAET6Q8lrCRTcjFLlLImluK3iXJW/hT47KGklS8OlzWUtXLFYDRCSS74ojUjxggqKMoxd6A1lTCyvsvyzC5/d7BsCHb7yIcHyrX2yR/NPnsAdRT2i0Pwp/o0Il6ix8hsRAuJmQgcr4KREfAiMgUVm9KqmfSxL5pOJspVwwTiV6jiIAg1RMhHpERhbvwgGI34Hc49T7UeKZtXwEqJ+BAaoBneperJH0POs1u4dufwv8Gf+qcOfjyvX6ZIVgxE0Rw87YF3BSc9c7jsXfdjOBG7FwmSb39pfGRwu8IuvUjJNoTpFzkEvDg6W3Qt/9nf99ZXPy8HM43IweTKyNR+WVatXcWWyakBksj9cqW+QetplcjsKElvZH/zuOO/PrCx//tL3/6x/O/C1PZZvSKuulLcS4l8M1ewGPR6ef5sllXW2eGQZ7hVSEZiPmcqrSS8e2ElX8o7t1fvB9LFetmEx5hx1Xuye2PpfjZnSjj7QfKTB3bZZo05Zvh6YuivX24cpc8+ddvADWG9odrSwFalVurxUiidDHmTiaoNkkh2gjbcpxMiAbd39aVP119/N9k4+euNKfcNjwaPhZEuUupUsJrHchw1LkPrRC9bQKa3M8Mj/xx903drdnHMpbirj1ENsUre0oo3N+7gat+2ZctKdsIUYc21sRu+Ucdhn+P7DyarftW00iu3Tmbv+hTfdCTmyaIPT4PrYZDFtBN2W8S9m4oTB5Z2P3Oe7weKjVBq86kXX/r0+WuvTAzfjqm1hsYRPWlbxm4n3IaeGOJEizv8orH9w5ejjmSrfOuEq/HxT6eDemtsZ/HTvvG1/8iVspxZILrlkz/cdsIbIroOgJileFSty2xiHNW5t9fbHJ3ze87bp5T9vc8RuqMB0ReDSt464R/BJxspvgpEsrVAJMTsYg2QovPTOHrvQ9et/S2Xx+40z7dY4JBX0Pz/ElH/T73U2DkK8EiqC9hM/zV3frQfzjaAqO16s1l6xCUXnBFlYxyIer3eEdth7u5xsHKxWoGLqzY3wIULt9G3K6soei9jZ+UcF+Ka3M/II9EUWrJ/LLxy+Q9xIh0vOl3NZCrVnBsuFUTOSnJnSioRWZ9q4g+ZDk5XVORoW2qX2hbIkna3JOrdR3jmpHVLovUkLES6grRO010u0GkDlX7SpH1DQ64Wl2zaSUJv1Mtti2G7kx5IyftWMhfDlGClcxvIUhP5crhp9LIb1Vne187oSAWxelcR/kXjYQTZboW+Oj1pqF0gmfZhSDD6bSgzGWrw3s7QLNtCV+2uatYrd/aFtjDI8R52e/DdyKgRKXBhEak3Ev50+GCUA9EFUor39htVMxmWvW8AM6ptG416rZvdWn+MarIEyH5r6ruZSrx8XrWDP370vbfTjqpmZGIbiFPFoihc4jcrlYi9p3ndSuymZ+XLaKza/P/HUWHn5Axdkd9OjBskY0+pIlz4AlFPFs+aStK5PBIRR4MVVJDihsy4JdEA4pVcrVqMZDyL2/8aYocikEAR9Xjc1BNG9zEiJG7n/cGyrtnblkClBhEgMW4Kx21BEBGJjLa0hcOGmTK64KsKLfKr9QyQELclxY3hqowTIZKdZNTSS5BWiBPlKxDWBVSS41bOepkhTkhGDajLfLyUBOKlkMHPgOhx3JoRN/cEiRgSWdgF2yCyDQu4IcbNo8ftTzxveOJ5y+h509h52+h549h569h587/M20f/b1AB
|
||||||
|
created: 20251110102157310
|
||||||
|
first-sighting: 2009-11-14
|
||||||
|
fullname: Mario Pietsch
|
||||||
|
github: pmario
|
||||||
|
homepage: https://wikilabs.github.io/
|
||||||
|
modified: 20251110124935183
|
||||||
|
tags: Community/Person Community/Team/Contributors
|
||||||
|
talk.tiddlywiki.org: pmario
|
||||||
|
title: @pmario
|
||||||
|
type: text/vnd.tiddlywiki
|
||||||
|
youtube: https://www.youtube.com/@pmario
|
||||||
|
|
||||||
|
''Hi, My name is Mario Pietsch''. Back in 2009 I was ''searching'' for ''a simple presentation tool'' and discovered ~TiddlyWiki Classic, Monkey Pirate ~TiddlyWiki ([[MPTW|https://mptw.tiddlyspot.com/]]) with ~TagglyTagging, Eric Shulman's ~TiddlyTools, Saq Imtiaz's navigation macros, and more. --- ''I was captivated''.
|
||||||
|
|
||||||
|
After a deep dive, I combined these elements into my own "Presentation Manager", along [[3 step by step tutorials|https://groups.google.com/g/tiddlywiki/c/qG_tZ1x0MEU/m/-vLA0luMicYJ]] to help others build it.
|
||||||
|
|
||||||
|
Thanks to ''the positive spirit'' of the ~TiddlyWiki community, I am proud to be part of it since 2009.
|
||||||
|
|
||||||
|
When Jeremy started developing ~TiddlyWiki 5 on ~GitHub, I joined in—opening [[issue no. 1|https://github.com/TiddlyWiki/TiddlyWiki5/issues/1]] all the way up to 13. For what that’s good ;) Since then, I have submitted nearly 600 pull requests and more than 500 issues, many of which have been merged or resolved.
|
||||||
|
|
||||||
|
My ~TiddlyWiki 5 "laboratory" is at https://wikilabs.github.io, and I also share content on my ''~YouTube'' channel: https://www.youtube.com/@pmario
|
||||||
|
|
||||||
|
Have fun!<br>
|
||||||
|
Mario
|
||||||
10
community/project/TiddlyWiki People.tid
Normal file
10
community/project/TiddlyWiki People.tid
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
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]]">>
|
||||||
10
community/project/TiddlyWiki Project.tid
Normal file
10
community/project/TiddlyWiki Project.tid
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
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"/>
|
||||||
4
community/project/Vacant Positions.tid
Normal file
4
community/project/Vacant Positions.tid
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
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">>.
|
||||||
8
community/project/teams/Core Team.tid
Normal file
8
community/project/teams/Core Team.tid
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
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.
|
||||||
19
community/project/teams/Developer Experience Team.tid
Normal file
19
community/project/teams/Developer Experience Team.tid
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
title: Developer Experience Team
|
||||||
|
tags: Community/Team
|
||||||
|
modified: 20251109200632671
|
||||||
|
created: 20251109200632671
|
||||||
|
leader: @pmario
|
||||||
|
team: @saqimtiaz
|
||||||
|
|
||||||
|
The Developer Experience Team improves the experience of software contributors to the TiddlyWiki project. This includes enhancing documentation, streamlining contribution processes, and providing tools and resources to help developers effectively contribute to TiddlyWiki.
|
||||||
|
|
||||||
|
Tools and resources managed by the Developer Experience Team include:
|
||||||
|
|
||||||
|
* Advising and assisting contributors, particularly new developers
|
||||||
|
* Maintenance of developer-focused documentation on the https://tiddlywiki.com/dev/ site, including:
|
||||||
|
** Development environment setup guides
|
||||||
|
** Code review processes and best practices
|
||||||
|
** Contribution guidelines and documentation
|
||||||
|
* Continuous integration and deployment scripts providing feedback on pull requests
|
||||||
|
* Devising and implementing labelling systems for issues and pull requests
|
||||||
|
* Automation scripts to simplify common development tasks
|
||||||
15
community/project/teams/Infrastructure Team.tid
Normal file
15
community/project/teams/Infrastructure Team.tid
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
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
|
||||||
8
community/project/teams/MultiWikiServer Team.tid
Normal file
8
community/project/teams/MultiWikiServer Team.tid
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
title: MultiWikiServer Team
|
||||||
|
tags: Community/Team
|
||||||
|
modified: 20250909171928024
|
||||||
|
created: 20250909171928024
|
||||||
|
leader: @Arlen22
|
||||||
|
team:
|
||||||
|
|
||||||
|
The MultiWikiServer development repository is at https://github.com/TiddlyWiki/MultiWikiServer
|
||||||
6
community/project/teams/Newsletter Team.tid
Normal file
6
community/project/teams/Newsletter Team.tid
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
title: Newsletter Team
|
||||||
|
tags: Community/Team
|
||||||
|
modified: 20250909171928024
|
||||||
|
created: 20250909171928024
|
||||||
|
|
||||||
|
The Newsletter Team is responsible for producing the TiddlyWiki Newsletter, a monthly email newsletter that highlights news, updates, and community contributions related to TiddlyWiki.
|
||||||
15
community/project/teams/Project Team.tid
Normal file
15
community/project/teams/Project Team.tid
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
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...
|
||||||
11
community/project/teams/Quality Assurance Team.tid
Normal file
11
community/project/teams/Quality Assurance Team.tid
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
title: Quality Assurance Team
|
||||||
|
created: 20251112125742296
|
||||||
|
modified: 20251112125742296
|
||||||
|
tags: Community/Team
|
||||||
|
team:
|
||||||
|
leader: @Leilei332
|
||||||
|
|
||||||
|
title: Quality Assurance Team
|
||||||
|
|
||||||
|
The Quality Assurance Team is responsible for ensuring the quality and reliability of TiddlyWiki releases. This includes reviewing code submissions, testing new features, identifying bugs, and verifying that fixes are effective.
|
||||||
|
|
||||||
13
community/project/teams/Succession Team.tid
Normal file
13
community/project/teams/Succession Team.tid
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
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
|
||||||
|
|
||||||
5
community/project/teams/tagCommunityTeam.tid
Normal file
5
community/project/teams/tagCommunityTeam.tid
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
title: Community/Team
|
||||||
|
modified: 20250909171928024
|
||||||
|
created: 20250909171928024
|
||||||
|
list: [[Project Team]] [[Core Team]] [[Documentation Team]] [[Quality Assurance Team]] [[Infrastructure Team]] [[MultiWikiServer Team]] [[Newsletter Team]] [[Succession Team]]
|
||||||
|
|
||||||
3
community/readme.md
Normal file
3
community/readme.md
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# 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.
|
||||||
15
community/tools/cards/DefaultColourMappings.multids
Normal file
15
community/tools/cards/DefaultColourMappings.multids
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
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
|
||||||
168
community/tools/cards/Procedures.tid
Normal file
168
community/tools/cards/Procedures.tid
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
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
|
||||||
158
community/tools/cards/Styles.tid
Normal file
158
community/tools/cards/Styles.tid
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
6
community/tools/cards/ViewTemplateBodyCascade.tid
Normal file
6
community/tools/cards/ViewTemplateBodyCascade.tid
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
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]]
|
||||||
3
community/tools/cards/ViewTemplateBodyTemplatePerson.tid
Normal file
3
community/tools/cards/ViewTemplateBodyTemplatePerson.tid
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
title: $:/tiddlywiki/community/cards/ViewTemplateBodyTemplatePerson
|
||||||
|
|
||||||
|
<$transclude $variable="community-card-person" title=<<currentTiddler>>/>
|
||||||
3
community/tools/cards/ViewTemplateBodyTemplateTeam.tid
Normal file
3
community/tools/cards/ViewTemplateBodyTemplateTeam.tid
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
title: $:/tiddlywiki/community/cards/ViewTemplateBodyTemplateTeam
|
||||||
|
|
||||||
|
<$transclude $variable="community-card-team" title=<<currentTiddler>>/>
|
||||||
7
community/tools/icons/person.tid
Normal file
7
community/tools/icons/person.tid
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
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>
|
||||||
7
community/tools/icons/project-team.tid
Normal file
7
community/tools/icons/project-team.tid
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
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>
|
||||||
9
community/tools/icons/team.tid
Normal file
9
community/tools/icons/team.tid
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
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>
|
||||||
|
|
@ -99,16 +99,18 @@ Commander.prototype.executeNextCommand = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(command.info.synchronous) {
|
if(command.info.synchronous) {
|
||||||
// Synchronous command
|
// Synchronous command (await thenables)
|
||||||
c = new command.Command(params,this);
|
c = new command.Command(params,this);
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { e ? this.callback(e) : this.executeNextCommand(); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
} else {
|
} else {
|
||||||
this.executeNextCommand();
|
this.executeNextCommand();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Asynchronous command
|
// Asynchronous command (await thenables)
|
||||||
c = new command.Command(params,this,function(err) {
|
c = new command.Command(params,this,function(err) {
|
||||||
if(err) {
|
if(err) {
|
||||||
self.callback(err);
|
self.callback(err);
|
||||||
|
|
@ -117,7 +119,9 @@ Commander.prototype.executeNextCommand = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
err = c.execute();
|
err = c.execute();
|
||||||
if(err) {
|
if(err && typeof err.then === "function") {
|
||||||
|
err.then(e => { if(e) this.callback(e); });
|
||||||
|
} else if(err) {
|
||||||
this.callback(err);
|
this.callback(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +76,7 @@ WikiFolderMaker.prototype.tiddlersToIgnore = [
|
||||||
"$:/boot/boot.js",
|
"$:/boot/boot.js",
|
||||||
"$:/boot/bootprefix.js",
|
"$:/boot/bootprefix.js",
|
||||||
"$:/core",
|
"$:/core",
|
||||||
|
"$:/core-server",
|
||||||
"$:/library/sjcl.js",
|
"$:/library/sjcl.js",
|
||||||
"$:/temp/info-plugin"
|
"$:/temp/info-plugin"
|
||||||
];
|
];
|
||||||
11
core-server/plugin.info
Normal file
11
core-server/plugin.info
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"title": "$:/core-server",
|
||||||
|
"name": "Core Server Components",
|
||||||
|
"description": "TiddlyWiki5 core server components",
|
||||||
|
"author": "JeremyRuston",
|
||||||
|
"core-version": ">=5.0.0",
|
||||||
|
"platform": "server",
|
||||||
|
"plugin-priority": "0",
|
||||||
|
"list": "readme",
|
||||||
|
"stability": "STABILITY_2_STABLE"
|
||||||
|
}
|
||||||
7
core-server/readme.tid
Normal file
7
core-server/readme.tid
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
title: $:/core-server/readme
|
||||||
|
|
||||||
|
This plugin contains TiddlyWiki's core components that are only needed on the server, comprising:
|
||||||
|
|
||||||
|
* Commands
|
||||||
|
* HTTP server code
|
||||||
|
* Utility functions for server
|
||||||
|
|
@ -8,10 +8,14 @@ DELETE /recipes/default/tiddlers/:title
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "DELETE";
|
exports.methods = ["DELETE"];
|
||||||
|
|
||||||
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/bags\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||||
state.wiki.deleteTiddler(title);
|
state.wiki.deleteTiddler(title);
|
||||||
|
|
@ -8,10 +8,14 @@ GET /favicon.ico
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/favicon.ico$/;
|
exports.path = /^\/favicon.ico$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
var buffer = state.wiki.getTiddlerText("$:/favicon.ico","");
|
||||||
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
state.sendResponse(200,{"Content-Type": "image/x-icon"},buffer,"base64");
|
||||||
73
core-server/server/routes/get-file.js
Normal file
73
core-server/server/routes/get-file.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/server/routes/get-file.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: route
|
||||||
|
|
||||||
|
GET /files/:filepath
|
||||||
|
|
||||||
|
\*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
|
exports.path = /^\/files\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.handler = function(request,response,state) {
|
||||||
|
var path = require("path"),
|
||||||
|
fs = require("fs"),
|
||||||
|
suppliedFilename = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
|
baseFilename = path.resolve(state.boot.wikiPath,"files"),
|
||||||
|
filename = path.resolve(baseFilename,suppliedFilename),
|
||||||
|
extension = path.extname(filename);
|
||||||
|
// Check that the filename is inside the wiki files folder
|
||||||
|
if(path.relative(baseFilename,filename).indexOf("..") === 0) {
|
||||||
|
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||||
|
}
|
||||||
|
fs.stat(filename, function(err, stats) {
|
||||||
|
if(err) {
|
||||||
|
return state.sendResponse(404,{"Content-Type": "text/plain"},"File '" + suppliedFilename + "' not found");
|
||||||
|
} else {
|
||||||
|
var type = ($tw.config.fileExtensionInfo[extension] ? $tw.config.fileExtensionInfo[extension].type : "application/octet-stream"),
|
||||||
|
responseHeaders = {
|
||||||
|
"Content-Type": type,
|
||||||
|
"Accept-Ranges": "bytes"
|
||||||
|
};
|
||||||
|
var rangeHeader = request.headers.range,
|
||||||
|
stream;
|
||||||
|
if(rangeHeader) {
|
||||||
|
// Handle range requests
|
||||||
|
var parts = rangeHeader.replace(/bytes=/, "").split("-"),
|
||||||
|
start = parseInt(parts[0], 10),
|
||||||
|
end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
|
||||||
|
// Validate start and end
|
||||||
|
if(isNaN(start) || isNaN(end) || start < 0 || end < start || end >= stats.size) {
|
||||||
|
responseHeaders["Content-Range"] = "bytes */" + stats.size;
|
||||||
|
return response.writeHead(416, responseHeaders).end();
|
||||||
|
}
|
||||||
|
var chunksize = (end - start) + 1;
|
||||||
|
responseHeaders["Content-Range"] = "bytes " + start + "-" + end + "/" + stats.size;
|
||||||
|
responseHeaders["Content-Length"] = chunksize;
|
||||||
|
response.writeHead(206, responseHeaders);
|
||||||
|
stream = fs.createReadStream(filename, {start: start, end: end});
|
||||||
|
} else {
|
||||||
|
responseHeaders["Content-Length"] = stats.size;
|
||||||
|
response.writeHead(200, responseHeaders);
|
||||||
|
stream = fs.createReadStream(filename);
|
||||||
|
}
|
||||||
|
// Common stream error handling
|
||||||
|
stream.on("error", function(err) {
|
||||||
|
if(!response.headersSent) {
|
||||||
|
response.writeHead(500, {"Content-Type": "text/plain"});
|
||||||
|
response.end("Read error");
|
||||||
|
} else {
|
||||||
|
response.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
stream.pipe(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -8,10 +8,14 @@ GET /
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/$/;
|
exports.path = /^\/$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
var text = state.wiki.renderTiddler(state.server.get("root-render-type"),state.server.get("root-tiddler")),
|
||||||
responseHeaders = {
|
responseHeaders = {
|
||||||
|
|
@ -8,10 +8,14 @@ GET /login-basic -- force a Basic Authentication challenge
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/login-basic$/;
|
exports.path = /^\/login-basic$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
if(!state.authenticatedUsername) {
|
if(!state.authenticatedUsername) {
|
||||||
// Challenge if there's no username
|
// Challenge if there's no username
|
||||||
|
|
@ -8,10 +8,14 @@ GET /status
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/status$/;
|
exports.path = /^\/status$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var text = JSON.stringify({
|
var text = JSON.stringify({
|
||||||
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
username: state.authenticatedUsername || state.server.get("anon-username") || "",
|
||||||
|
|
@ -8,10 +8,14 @@ GET /:title
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/([^\/]+)$/;
|
exports.path = /^\/([^\/]+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title);
|
tiddler = state.wiki.getTiddler(title);
|
||||||
|
|
@ -8,10 +8,14 @@ GET /recipes/default/tiddlers/:title
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
tiddler = state.wiki.getTiddler(title),
|
tiddler = state.wiki.getTiddler(title),
|
||||||
|
|
@ -10,10 +10,14 @@ GET /recipes/default/tiddlers.json?filter=<filter>
|
||||||
|
|
||||||
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
var DEFAULT_FILTER = "[all[tiddlers]!is[system]sort[title]]";
|
||||||
|
|
||||||
exports.method = "GET";
|
exports.methods = ["GET"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
exports.path = /^\/recipes\/default\/tiddlers.json$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
var filter = state.queryParameters.filter || DEFAULT_FILTER;
|
||||||
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
if(state.wiki.getTiddlerText("$:/config/Server/AllowAllExternalFilters") !== "yes") {
|
||||||
|
|
@ -8,10 +8,14 @@ PUT /recipes/default/tiddlers/:title
|
||||||
\*/
|
\*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.method = "PUT";
|
exports.methods = ["PUT"];
|
||||||
|
|
||||||
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
exports.path = /^\/recipes\/default\/tiddlers\/(.+)$/;
|
||||||
|
|
||||||
|
exports.info = {
|
||||||
|
priority: 100
|
||||||
|
};
|
||||||
|
|
||||||
exports.handler = function(request,response,state) {
|
exports.handler = function(request,response,state) {
|
||||||
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
var title = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||||
fields = $tw.utils.parseJSONSafe(state.data);
|
fields = $tw.utils.parseJSONSafe(state.data);
|
||||||
|
|
@ -74,6 +74,11 @@ function Server(options) {
|
||||||
// console.log("Loading server route " + title);
|
// console.log("Loading server route " + title);
|
||||||
self.addRoute(routeDefinition);
|
self.addRoute(routeDefinition);
|
||||||
});
|
});
|
||||||
|
this.routes.sort((a, b) => {
|
||||||
|
const priorityA = a.info?.priority ?? 100,
|
||||||
|
priorityB = b.info?.priority ?? 100;
|
||||||
|
return priorityB - priorityA;
|
||||||
|
});
|
||||||
// Initialise the http vs https
|
// Initialise the http vs https
|
||||||
this.listenOptions = null;
|
this.listenOptions = null;
|
||||||
this.protocol = "http";
|
this.protocol = "http";
|
||||||
|
|
@ -217,7 +222,7 @@ Server.prototype.findMatchingRoute = function(request,state) {
|
||||||
} else {
|
} else {
|
||||||
match = potentialRoute.path.exec(pathname);
|
match = potentialRoute.path.exec(pathname);
|
||||||
}
|
}
|
||||||
if(match && request.method === potentialRoute.method) {
|
if(match && (potentialRoute.methods?.includes(request.method) || potentialRoute.method === request.method)) {
|
||||||
state.params = [];
|
state.params = [];
|
||||||
for(var p=1; p<match.length; p++) {
|
for(var p=1; p<match.length; p++) {
|
||||||
state.params.push(match[p]);
|
state.params.push(match[p]);
|
||||||
|
|
@ -4,4 +4,4 @@ TiddlyWiki incorporates code from these fine OpenSource projects:
|
||||||
|
|
||||||
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
* [[The Stanford Javascript Crypto Library|http://bitwiseshiftleft.github.io/sjcl/]]
|
||||||
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
* [[The Jasmine JavaScript Test Framework|https://jasmine.github.io/]]
|
||||||
* [[Normalize.css by Nicolas Gallagher|http://necolas.github.io/normalize.css/]]
|
* [[modern-normalize by Sindre Sorhus|https://github.com/sindresorhus/modern-normalize]]
|
||||||
|
|
|
||||||
|
|
@ -131,15 +131,14 @@ 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/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/Advanced/Heading: Advanced Settings
|
||||||
Saving/TiddlySpot/BackupDir: Backup Directory
|
Saving/TiddlySpot/BackupDir: Backup Directory
|
||||||
Saving/TiddlySpot/ControlPanel: ~TiddlySpot Control Panel
|
Saving/TiddlySpot/ControlPanel: ~TiddlyHost Control Panel
|
||||||
Saving/TiddlySpot/Backups: Backups
|
Saving/TiddlySpot/Backups: Backups
|
||||||
Saving/TiddlySpot/Caption: ~TiddlySpot Saver
|
Saving/TiddlySpot/Caption: ~TiddlyHost 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/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/Filename: Upload Filename
|
Saving/TiddlySpot/Filename: Upload Filename
|
||||||
Saving/TiddlySpot/Heading: ~TiddlySpot
|
Saving/TiddlySpot/Heading: ~TiddlyHost
|
||||||
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/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/Password: Password
|
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/ServerURL: Server URL
|
||||||
Saving/TiddlySpot/UploadDir: Upload Directory
|
Saving/TiddlySpot/UploadDir: Upload Directory
|
||||||
Saving/TiddlySpot/UserName: Wiki Name
|
Saving/TiddlySpot/UserName: Wiki Name
|
||||||
|
|
@ -148,7 +147,7 @@ Settings/AutoSave/Disabled/Description: Do not save changes automatically
|
||||||
Settings/AutoSave/Enabled/Description: Save changes automatically
|
Settings/AutoSave/Enabled/Description: Save changes automatically
|
||||||
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
Settings/AutoSave/Hint: Attempt to automatically save changes during editing when using a supporting saver
|
||||||
Settings/CamelCase/Caption: Camel Case Wiki Links
|
Settings/CamelCase/Caption: Camel Case Wiki Links
|
||||||
Settings/CamelCase/Hint: You can globally disable automatic linking of ~CamelCase phrases. Requires reload to take effect
|
Settings/CamelCase/Hint: Requires reload to take effect
|
||||||
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
Settings/CamelCase/Description: Enable automatic ~CamelCase linking
|
||||||
Settings/Caption: Settings
|
Settings/Caption: Settings
|
||||||
Settings/EditorToolbar/Caption: Editor Toolbar
|
Settings/EditorToolbar/Caption: Editor Toolbar
|
||||||
|
|
@ -190,6 +189,8 @@ Settings/DefaultSidebarTab/Caption: Default Sidebar Tab
|
||||||
Settings/DefaultSidebarTab/Hint: Specify which sidebar tab is displayed by default
|
Settings/DefaultSidebarTab/Hint: Specify which sidebar tab is displayed by default
|
||||||
Settings/DefaultMoreSidebarTab/Caption: Default More Sidebar Tab
|
Settings/DefaultMoreSidebarTab/Caption: Default More Sidebar Tab
|
||||||
Settings/DefaultMoreSidebarTab/Hint: Specify which More sidebar tab is displayed by default
|
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/Caption: Tiddler Opening Behaviour
|
||||||
Settings/LinkToBehaviour/InsideRiver/Hint: Navigation from //within// the story river
|
Settings/LinkToBehaviour/InsideRiver/Hint: Navigation from //within// the story river
|
||||||
Settings/LinkToBehaviour/OutsideRiver/Hint: Navigation from //outside// the story river
|
Settings/LinkToBehaviour/OutsideRiver/Hint: Navigation from //outside// the story river
|
||||||
|
|
@ -251,3 +252,6 @@ 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.
|
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/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.
|
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
|
||||||
|
|
@ -34,7 +34,7 @@ function FramedEngine(options) {
|
||||||
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
var paletteTitle = this.widget.wiki.getTiddlerText("$:/palette");
|
||||||
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
var colorScheme = (this.widget.wiki.getTiddler(paletteTitle) || {fields: {}}).fields["color-scheme"] || "light";
|
||||||
this.iframeDoc.open();
|
this.iframeDoc.open();
|
||||||
this.iframeDoc.write("<meta name='color-scheme' content='" + colorScheme + "'>");
|
this.iframeDoc.write("<!DOCTYPE html><html><head><meta name='color-scheme' content='" + colorScheme + "'></head><body></body></html>");
|
||||||
this.iframeDoc.close();
|
this.iframeDoc.close();
|
||||||
// Style the iframe
|
// Style the iframe
|
||||||
this.iframeNode.className = this.dummyTextArea.className;
|
this.iframeNode.className = this.dummyTextArea.className;
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) {
|
||||||
// Fix height
|
// Fix height
|
||||||
this.engine.fixHeight();
|
this.engine.fixHeight();
|
||||||
// Focus if required
|
// Focus if required
|
||||||
if(this.editFocus === "true" || this.editFocus === "yes") {
|
if($tw.browser && (this.editFocus === "true" || this.editFocus === "yes") && !$tw.utils.hasClass(this.parentDomNode.ownerDocument.activeElement,"tc-keep-focus")) {
|
||||||
this.engine.focus();
|
this.engine.focus();
|
||||||
}
|
}
|
||||||
// Add widget message listeners
|
// Add widget message listeners
|
||||||
|
|
|
||||||
41
core/modules/filterrunprefixes/let.js
Normal file
41
core/modules/filterrunprefixes/let.js
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/filterrunprefixes/let.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: filterrunprefix
|
||||||
|
|
||||||
|
Assign a value to a variable
|
||||||
|
|
||||||
|
\*/
|
||||||
|
|
||||||
|
/*jslint node: true, browser: true */
|
||||||
|
/*global $tw: false */
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Export our filter prefix function
|
||||||
|
*/
|
||||||
|
exports.let = function(operationSubFunction,options) {
|
||||||
|
// Return the filter run prefix function
|
||||||
|
return function(results,source,widget) {
|
||||||
|
// Save the result list
|
||||||
|
var resultList = results.toArray();
|
||||||
|
// Clear the results
|
||||||
|
results.clear();
|
||||||
|
// Evaluate the subfunction to get the variable name
|
||||||
|
var subFunctionResults = operationSubFunction(source,widget);
|
||||||
|
if(subFunctionResults.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var name = subFunctionResults[0];
|
||||||
|
if(typeof name !== "string" || name.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Assign the result of the subfunction to the variable
|
||||||
|
var variables = {};
|
||||||
|
variables[name] = resultList;
|
||||||
|
// Return the variables
|
||||||
|
return {
|
||||||
|
variables: variables
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -35,7 +35,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||||
operator.prefix = filterString.charAt(p++);
|
operator.prefix = filterString.charAt(p++);
|
||||||
}
|
}
|
||||||
// Get the operator name
|
// Get the operator name
|
||||||
nextBracketPos = filterString.substring(p).search(/[\[\{<\/]/);
|
nextBracketPos = filterString.substring(p).search(/[\[\{<\/\(]/);
|
||||||
if(nextBracketPos === -1) {
|
if(nextBracketPos === -1) {
|
||||||
throw "Missing [ in filter expression";
|
throw "Missing [ in filter expression";
|
||||||
}
|
}
|
||||||
|
|
@ -79,6 +79,10 @@ function parseFilterOperation(operators,filterString,p) {
|
||||||
operand.variable = true;
|
operand.variable = true;
|
||||||
nextBracketPos = filterString.indexOf(">",p);
|
nextBracketPos = filterString.indexOf(">",p);
|
||||||
break;
|
break;
|
||||||
|
case "(": // Round brackets
|
||||||
|
operand.multiValuedVariable = true;
|
||||||
|
nextBracketPos = filterString.indexOf(")",p);
|
||||||
|
break;
|
||||||
case "/": // regexp brackets
|
case "/": // regexp brackets
|
||||||
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
var rex = /^((?:[^\\\/]|\\.)*)\/(?:\(([mygi]+)\))?/g,
|
||||||
rexMatch = rex.exec(filterString.substring(p));
|
rexMatch = rex.exec(filterString.substring(p));
|
||||||
|
|
@ -112,7 +116,7 @@ function parseFilterOperation(operators,filterString,p) {
|
||||||
// Check for multiple operands
|
// Check for multiple operands
|
||||||
while(filterString.charAt(p) === ",") {
|
while(filterString.charAt(p) === ",") {
|
||||||
p++;
|
p++;
|
||||||
if(/^[\[\{<\/]/.test(filterString.substring(p))) {
|
if(/^[\[\{<\/\(]/.test(filterString.substring(p))) {
|
||||||
nextBracketPos = p;
|
nextBracketPos = p;
|
||||||
p++;
|
p++;
|
||||||
parseOperand(filterString.charAt(nextBracketPos));
|
parseOperand(filterString.charAt(nextBracketPos));
|
||||||
|
|
@ -141,7 +145,15 @@ exports.parseFilter = function(filterString) {
|
||||||
p = 0, // Current position in the filter string
|
p = 0, // Current position in the filter string
|
||||||
match;
|
match;
|
||||||
var whitespaceRegExp = /(\s+)/mg,
|
var whitespaceRegExp = /(\s+)/mg,
|
||||||
operandRegExp = /((?:\+|\-|~|=|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
// Groups:
|
||||||
|
// 1 - entire filter run prefix
|
||||||
|
// 2 - filter run prefix itself
|
||||||
|
// 3 - filter run prefix suffixes
|
||||||
|
// 4 - opening square bracket following filter run prefix
|
||||||
|
// 5 - double quoted string following filter run prefix
|
||||||
|
// 6 - single quoted string following filter run prefix
|
||||||
|
// 7 - anything except for whitespace and square brackets
|
||||||
|
operandRegExp = /((?:\+|\-|~|(?:=>?)|\:(\w+)(?:\:([\w\:, ]*))?)?)(?:(\[)|(?:"([^"]*)")|(?:'([^']*)')|([^\s\[\]]+))/mg;
|
||||||
while(p < filterString.length) {
|
while(p < filterString.length) {
|
||||||
// Skip any whitespace
|
// Skip any whitespace
|
||||||
whitespaceRegExp.lastIndex = p;
|
whitespaceRegExp.lastIndex = p;
|
||||||
|
|
@ -152,38 +164,45 @@ exports.parseFilter = function(filterString) {
|
||||||
// Match the start of the operation
|
// Match the start of the operation
|
||||||
if(p < filterString.length) {
|
if(p < filterString.length) {
|
||||||
operandRegExp.lastIndex = p;
|
operandRegExp.lastIndex = p;
|
||||||
match = operandRegExp.exec(filterString);
|
|
||||||
if(!match || match.index !== p) {
|
|
||||||
throw $tw.language.getString("Error/FilterSyntax");
|
|
||||||
}
|
|
||||||
var operation = {
|
var operation = {
|
||||||
prefix: "",
|
prefix: "",
|
||||||
operators: []
|
operators: []
|
||||||
};
|
};
|
||||||
if(match[1]) {
|
match = operandRegExp.exec(filterString);
|
||||||
operation.prefix = match[1];
|
if(match && match.index === p) {
|
||||||
p = p + operation.prefix.length;
|
// If there is a filter run prefix
|
||||||
if(match[2]) {
|
if(match[1]) {
|
||||||
operation.namedPrefix = match[2];
|
operation.prefix = match[1];
|
||||||
}
|
p = p + operation.prefix.length;
|
||||||
if(match[3]) {
|
// Name for named prefixes
|
||||||
operation.suffixes = [];
|
if(match[2]) {
|
||||||
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
operation.namedPrefix = match[2];
|
||||||
operation.suffixes.push([]);
|
}
|
||||||
$tw.utils.each(subsuffix.split(","),function(entry) {
|
// Suffixes for filter run prefix
|
||||||
entry = $tw.utils.trim(entry);
|
if(match[3]) {
|
||||||
if(entry) {
|
operation.suffixes = [];
|
||||||
operation.suffixes[operation.suffixes.length -1].push(entry);
|
$tw.utils.each(match[3].split(":"),function(subsuffix) {
|
||||||
}
|
operation.suffixes.push([]);
|
||||||
|
$tw.utils.each(subsuffix.split(","),function(entry) {
|
||||||
|
entry = $tw.utils.trim(entry);
|
||||||
|
if(entry) {
|
||||||
|
operation.suffixes[operation.suffixes.length -1].push(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
// Opening square bracket
|
||||||
|
if(match[4]) {
|
||||||
|
p = parseFilterOperation(operation.operators,filterString,p);
|
||||||
|
} else {
|
||||||
|
p = match.index + match[0].length;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(match[4]) { // Opening square bracket
|
|
||||||
p = parseFilterOperation(operation.operators,filterString,p);
|
|
||||||
} else {
|
} else {
|
||||||
p = match.index + match[0].length;
|
// No filter run prefix
|
||||||
|
p = parseFilterOperation(operation.operators,filterString,p);
|
||||||
}
|
}
|
||||||
|
// Quoted strings and unquoted title
|
||||||
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
if(match[5] || match[6] || match[7]) { // Double quoted string, single quoted string or unquoted title
|
||||||
operation.operators.push(
|
operation.operators.push(
|
||||||
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
{operator: "title", operands: [{text: match[5] || match[6] || match[7]}]}
|
||||||
|
|
@ -248,10 +267,11 @@ exports.compileFilter = function(filterString) {
|
||||||
// Create a function for the chain of operators in the operation
|
// Create a function for the chain of operators in the operation
|
||||||
var operationSubFunction = function(source,widget) {
|
var operationSubFunction = function(source,widget) {
|
||||||
var accumulator = source,
|
var accumulator = source,
|
||||||
results = [],
|
results = [];
|
||||||
currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
|
||||||
$tw.utils.each(operation.operators,function(operator) {
|
$tw.utils.each(operation.operators,function(operator) {
|
||||||
var operands = [],
|
var operands = [],
|
||||||
|
multiValueOperands = [],
|
||||||
|
isMultiValueOperand = [],
|
||||||
operatorFunction;
|
operatorFunction;
|
||||||
if(!operator.operator) {
|
if(!operator.operator) {
|
||||||
// Use the "title" operator if no operator is specified
|
// Use the "title" operator if no operator is specified
|
||||||
|
|
@ -265,14 +285,31 @@ exports.compileFilter = function(filterString) {
|
||||||
}
|
}
|
||||||
$tw.utils.each(operator.operands,function(operand) {
|
$tw.utils.each(operator.operands,function(operand) {
|
||||||
if(operand.indirect) {
|
if(operand.indirect) {
|
||||||
|
var currTiddlerTitle = widget && widget.getVariable("currentTiddler");
|
||||||
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
operand.value = self.getTextReference(operand.text,"",currTiddlerTitle);
|
||||||
|
operand.multiValue = [operand.value];
|
||||||
} else if(operand.variable) {
|
} else if(operand.variable) {
|
||||||
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||||
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
operand.value = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source})[0] || "";
|
||||||
|
operand.multiValue = [operand.value];
|
||||||
|
} else if(operand.multiValuedVariable) {
|
||||||
|
var varTree = $tw.utils.parseFilterVariable(operand.text);
|
||||||
|
var resultList = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source});
|
||||||
|
if((resultList.length > 0 && resultList[0] !== undefined) || resultList.length === 0) {
|
||||||
|
operand.multiValue = widgetClass.evaluateVariable(widget,varTree.name,{params: varTree.params, source: source}) || [];
|
||||||
|
operand.value = operand.multiValue[0] || "";
|
||||||
|
} else {
|
||||||
|
operand.value = "";
|
||||||
|
operand.multiValue = [];
|
||||||
|
}
|
||||||
|
operand.isMultiValueOperand = true;
|
||||||
} else {
|
} else {
|
||||||
operand.value = operand.text;
|
operand.value = operand.text;
|
||||||
|
operand.multiValue = [operand.value];
|
||||||
}
|
}
|
||||||
operands.push(operand.value);
|
operands.push(operand.value);
|
||||||
|
multiValueOperands.push(operand.multiValue);
|
||||||
|
isMultiValueOperand.push(!!operand.isMultiValueOperand);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Invoke the appropriate filteroperator module
|
// Invoke the appropriate filteroperator module
|
||||||
|
|
@ -280,6 +317,8 @@ exports.compileFilter = function(filterString) {
|
||||||
operator: operator.operator,
|
operator: operator.operator,
|
||||||
operand: operands.length > 0 ? operands[0] : undefined,
|
operand: operands.length > 0 ? operands[0] : undefined,
|
||||||
operands: operands,
|
operands: operands,
|
||||||
|
multiValueOperands: multiValueOperands,
|
||||||
|
isMultiValueOperand: isMultiValueOperand,
|
||||||
prefix: operator.prefix,
|
prefix: operator.prefix,
|
||||||
suffix: operator.suffix,
|
suffix: operator.suffix,
|
||||||
suffixes: operator.suffixes,
|
suffixes: operator.suffixes,
|
||||||
|
|
@ -319,6 +358,8 @@ exports.compileFilter = function(filterString) {
|
||||||
return filterRunPrefixes["and"](operationSubFunction, options);
|
return filterRunPrefixes["and"](operationSubFunction, options);
|
||||||
case "~": // This operation is unioned into the result only if the main result so far is empty
|
case "~": // This operation is unioned into the result only if the main result so far is empty
|
||||||
return filterRunPrefixes["else"](operationSubFunction, options);
|
return filterRunPrefixes["else"](operationSubFunction, options);
|
||||||
|
case "=>": // This operation is applied to the main results so far, and the results are assigned to a variable
|
||||||
|
return filterRunPrefixes["let"](operationSubFunction, options);
|
||||||
default:
|
default:
|
||||||
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
if(operation.namedPrefix && filterRunPrefixes[operation.namedPrefix]) {
|
||||||
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
return filterRunPrefixes[operation.namedPrefix](operationSubFunction, options);
|
||||||
|
|
@ -345,7 +386,13 @@ exports.compileFilter = function(filterString) {
|
||||||
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
self.filterRecursionCount = (self.filterRecursionCount || 0) + 1;
|
||||||
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
if(self.filterRecursionCount < MAX_FILTER_DEPTH) {
|
||||||
$tw.utils.each(operationFunctions,function(operationFunction) {
|
$tw.utils.each(operationFunctions,function(operationFunction) {
|
||||||
operationFunction(results,source,widget);
|
var operationResult = operationFunction(results,source,widget);
|
||||||
|
if(operationResult) {
|
||||||
|
if(operationResult.variables) {
|
||||||
|
// If the filter run prefix has returned variables, create a new fake widget with those variables
|
||||||
|
widget = widget.makeFakeWidgetWithVariables(operationResult.variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push("/**-- Excessive filter recursion --**/");
|
results.push("/**-- Excessive filter recursion --**/");
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,8 @@ exports.json = function(source,operand,options) {
|
||||||
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
spaces = /^\d+$/.test(operand) ? parseInt(operand,10) : operand;
|
||||||
}
|
}
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
var data = $tw.utils.parseJSONSafe(title);
|
var data = $tw.utils.parseJSONSafe(title,function(){return undefined;});
|
||||||
try {
|
|
||||||
data = JSON.parse(title);
|
|
||||||
} catch(e) {
|
|
||||||
data = undefined;
|
|
||||||
}
|
|
||||||
if(data !== undefined) {
|
if(data !== undefined) {
|
||||||
results.push(JSON.stringify(data,null,spaces));
|
results.push(JSON.stringify(data,null,spaces));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ exports.function = function(source,operator,options) {
|
||||||
var functionName = operator.operands[0],
|
var functionName = operator.operands[0],
|
||||||
params = [],
|
params = [],
|
||||||
results;
|
results;
|
||||||
$tw.utils.each(operator.operands.slice(1),function(param) {
|
$tw.utils.each(operator.multiValueOperands.slice(1),function(paramList) {
|
||||||
params.push({value: param});
|
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||||
});
|
});
|
||||||
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
// console.log(`Calling ${functionName} with params ${JSON.stringify(params)}`);
|
||||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(functionName,{params: params, source: source});
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,22 @@ exports["jsonset"] = function(source,operator,options) {
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports["jsondelete"] = function(source,operator,options) {
|
||||||
|
var indexes = operator.operands,
|
||||||
|
results = [];
|
||||||
|
source(function(tiddler,title) {
|
||||||
|
var data = $tw.utils.parseJSONSafe(title,title);
|
||||||
|
// If parsing failed (data equals original title and is a string), return unchanged
|
||||||
|
if(data === title && typeof data === "string") {
|
||||||
|
results.push(title);
|
||||||
|
} else if(data) {
|
||||||
|
data = deleteDataItem(data,indexes);
|
||||||
|
results.push(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
Given a JSON data structure and an array of index strings, return an array of the string representation of the values at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||||
*/
|
*/
|
||||||
|
|
@ -144,7 +160,7 @@ function convertDataItemValueToStrings(item) {
|
||||||
return ["null"]
|
return ["null"]
|
||||||
} else if(typeof item === "object") {
|
} else if(typeof item === "object") {
|
||||||
var results = [],i,t;
|
var results = [],i,t;
|
||||||
if($tw.utils.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
// Return all the items in arrays recursively
|
// Return all the items in arrays recursively
|
||||||
for(i=0; i<item.length; i++) {
|
for(i=0; i<item.length; i++) {
|
||||||
t = convertDataItemValueToStrings(item[i])
|
t = convertDataItemValueToStrings(item[i])
|
||||||
|
|
@ -178,7 +194,7 @@ function convertDataItemKeysToStrings(item) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
var results = [];
|
var results = [];
|
||||||
if($tw.utils.isArray(item)) {
|
if(Array.isArray(item)) {
|
||||||
for(var i=0; i<item.length; i++) {
|
for(var i=0; i<item.length; i++) {
|
||||||
results.push(i.toString());
|
results.push(i.toString());
|
||||||
}
|
}
|
||||||
|
|
@ -201,7 +217,7 @@ function getDataItemType(data,indexes) {
|
||||||
return item;
|
return item;
|
||||||
} else if(item === null) {
|
} else if(item === null) {
|
||||||
return "null";
|
return "null";
|
||||||
} else if($tw.utils.isArray(item)) {
|
} else if(Array.isArray(item)) {
|
||||||
return "array";
|
return "array";
|
||||||
} else if(typeof item === "object") {
|
} else if(typeof item === "object") {
|
||||||
return "object";
|
return "object";
|
||||||
|
|
@ -213,7 +229,7 @@ function getDataItemType(data,indexes) {
|
||||||
function getItemAtIndex(item,index) {
|
function getItemAtIndex(item,index) {
|
||||||
if($tw.utils.hop(item,index)) {
|
if($tw.utils.hop(item,index)) {
|
||||||
return item[index];
|
return item[index];
|
||||||
} else if($tw.utils.isArray(item)) {
|
} else if(Array.isArray(item)) {
|
||||||
index = $tw.utils.parseInt(index);
|
index = $tw.utils.parseInt(index);
|
||||||
if(index < 0) { index = index + item.length };
|
if(index < 0) { index = index + item.length };
|
||||||
return item[index]; // Will be undefined if index was out-of-bounds
|
return item[index]; // Will be undefined if index was out-of-bounds
|
||||||
|
|
@ -223,15 +239,16 @@ function getItemAtIndex(item,index) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
Traverse the index chain and return the item at the specified depth.
|
||||||
|
Returns the item at the end of the traversal, or undefined if traversal fails.
|
||||||
*/
|
*/
|
||||||
function getDataItem(data,indexes) {
|
function traverseIndexChain(data,indexes,stopBeforeLast) {
|
||||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
// Get the item
|
|
||||||
var item = data;
|
var item = data;
|
||||||
for(var i=0; i<indexes.length; i++) {
|
var stopIndex = stopBeforeLast ? indexes.length - 1 : indexes.length;
|
||||||
|
for(var i = 0; i < stopIndex; i++) {
|
||||||
if(item !== undefined) {
|
if(item !== undefined) {
|
||||||
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
if(item !== null && ["number","string","boolean"].indexOf(typeof item) === -1) {
|
||||||
item = getItemAtIndex(item,indexes[i]);
|
item = getItemAtIndex(item,indexes[i]);
|
||||||
|
|
@ -243,6 +260,13 @@ function getDataItem(data,indexes) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a JSON data structure and an array of index strings, return the value at the end of the index chain, or "undefined" if any of the index strings are invalid
|
||||||
|
*/
|
||||||
|
function getDataItem(data,indexes) {
|
||||||
|
return traverseIndexChain(data,indexes,false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
Given a JSON data structure, an array of index strings and a value, return the data structure with the value added at the end of the index chain. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then a different data object will be returned
|
||||||
*/
|
*/
|
||||||
|
|
@ -255,18 +279,15 @@ function setDataItem(data,indexes,value) {
|
||||||
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
// Traverse the JSON data structure using the index chain
|
// Traverse the JSON data structure using the index chain up to the parent
|
||||||
var current = data;
|
var current = traverseIndexChain(data,indexes,true);
|
||||||
for(var i = 0; i < indexes.length - 1; i++) {
|
if(current === undefined) {
|
||||||
current = getItemAtIndex(current,indexes[i]);
|
// Return the original JSON data structure if any of the index strings are invalid
|
||||||
if(current === undefined) {
|
return data;
|
||||||
// Return the original JSON data structure if any of the index strings are invalid
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Add the value to the end of the index chain
|
// Add the value to the end of the index chain
|
||||||
var lastIndex = indexes[indexes.length - 1];
|
var lastIndex = indexes[indexes.length - 1];
|
||||||
if($tw.utils.isArray(current)) {
|
if(Array.isArray(current)) {
|
||||||
lastIndex = $tw.utils.parseInt(lastIndex);
|
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||||
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||||
}
|
}
|
||||||
|
|
@ -276,3 +297,32 @@ function setDataItem(data,indexes,value) {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Given a JSON data structure and an array of index strings, return the data structure with the item at the end of the index chain deleted. If any of the index strings are invalid then the JSON data structure is returned unmodified. If the root item is targetted then the JSON data structure is returned unmodified.
|
||||||
|
*/
|
||||||
|
function deleteDataItem(data,indexes) {
|
||||||
|
// Check for the root item - don't delete the root
|
||||||
|
if(indexes.length === 0 || (indexes.length === 1 && indexes[0] === "")) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// Traverse the JSON data structure using the index chain up to the parent
|
||||||
|
var current = traverseIndexChain(data,indexes,true);
|
||||||
|
if(current === undefined || current === null) {
|
||||||
|
// Return the original JSON data structure if any of the index strings are invalid
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// Delete the item at the end of the index chain
|
||||||
|
var lastIndex = indexes[indexes.length - 1];
|
||||||
|
if(Array.isArray(current) && current !== null) {
|
||||||
|
lastIndex = $tw.utils.parseInt(lastIndex);
|
||||||
|
if(lastIndex < 0) { lastIndex = lastIndex + current.length };
|
||||||
|
// Check if index is valid before splicing
|
||||||
|
if(lastIndex >= 0 && lastIndex < current.length) {
|
||||||
|
current.splice(lastIndex,1);
|
||||||
|
}
|
||||||
|
} else if(typeof current === "object" && current !== null) {
|
||||||
|
delete current[lastIndex];
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,10 @@ function makeNumericReducingOperator(fnCalc,initialValue,fnFinal) {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
result.push($tw.utils.parseNumber(title));
|
result.push($tw.utils.parseNumber(title));
|
||||||
});
|
});
|
||||||
|
// We return an empty array if there are no input titles
|
||||||
|
if(result.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
var value = result.reduce(function(accumulator,currentValue) {
|
var value = result.reduce(function(accumulator,currentValue) {
|
||||||
return fnCalc(accumulator,currentValue);
|
return fnCalc(accumulator,currentValue);
|
||||||
},initialValue);
|
},initialValue);
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@ exports.title = function(source,operator,options) {
|
||||||
var results = [];
|
var results = [];
|
||||||
if(operator.prefix === "!") {
|
if(operator.prefix === "!") {
|
||||||
source(function(tiddler,title) {
|
source(function(tiddler,title) {
|
||||||
if(tiddler && tiddler.fields.title !== operator.operand) {
|
var titleList = operator.multiValueOperands[0] || [];
|
||||||
|
if(tiddler && titleList.indexOf(tiddler.fields.title) === -1) {
|
||||||
results.push(title);
|
results.push(title);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
results.push(operator.operand);
|
Array.prototype.push.apply(results,operator.multiValueOperands[0]);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ exports["[unknown]"] = function(source,operator,options) {
|
||||||
// Check for a user defined filter operator
|
// Check for a user defined filter operator
|
||||||
if(operator.operator.indexOf(".") !== -1) {
|
if(operator.operator.indexOf(".") !== -1) {
|
||||||
var params = [];
|
var params = [];
|
||||||
$tw.utils.each(operator.operands,function(param) {
|
$tw.utils.each(operator.multiValueOperands,function(paramList) {
|
||||||
params.push({value: param});
|
params.push({value: paramList[0] || "",multiValue: paramList});
|
||||||
});
|
});
|
||||||
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
|
var variableInfo = options.widget && options.widget.getVariableInfo && options.widget.getVariableInfo(operator.operator,{params: params, source: source});
|
||||||
if(variableInfo && variableInfo.srcVariable) {
|
if(variableInfo && variableInfo.srcVariable) {
|
||||||
|
|
|
||||||
86
core/modules/info/dimensions.js
Normal file
86
core/modules/info/dimensions.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*\
|
||||||
|
title: $:/core/modules/info/windowdimensions.js
|
||||||
|
type: application/javascript
|
||||||
|
module-type: info
|
||||||
|
\*/
|
||||||
|
|
||||||
|
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
|
||||||
|
if(!$tw.browser) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindowDimensionsTracker {
|
||||||
|
constructor(updateCallback) {
|
||||||
|
this.updateCallback = updateCallback;
|
||||||
|
this.resizeHandlers = new Map();
|
||||||
|
this.dimensionsInfo = [
|
||||||
|
["outer/width", win => win.outerWidth],
|
||||||
|
["outer/height", win => win.outerHeight],
|
||||||
|
["inner/width", win => win.innerWidth],
|
||||||
|
["inner/height", win => win.innerHeight],
|
||||||
|
["client/width", win => win.document.documentElement.clientWidth],
|
||||||
|
["client/height", win => win.document.documentElement.clientHeight]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTiddlers(win,windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`;
|
||||||
|
return this.dimensionsInfo.map(([suffix, getter]) => ({
|
||||||
|
title: prefix + suffix,
|
||||||
|
text: String(getter(win))
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTiddlers(windowId) {
|
||||||
|
const prefix = `$:/info/browser/window/${windowId}/`,
|
||||||
|
deletions = this.dimensionsInfo.map(([suffix]) => prefix + suffix);
|
||||||
|
this.updateCallback([], deletions);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpdateHandler(win,windowId) {
|
||||||
|
let scheduled = false;
|
||||||
|
return () => {
|
||||||
|
if(!scheduled) {
|
||||||
|
scheduled = true;
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.updateCallback(this.buildTiddlers(win,windowId), []);
|
||||||
|
scheduled = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trackWindow(win,windowId) {
|
||||||
|
const handler = this.getUpdateHandler(win, windowId);
|
||||||
|
handler(); // initial update
|
||||||
|
win.addEventListener("resize",handler,{passive:true});
|
||||||
|
this.resizeHandlers.set(windowId,{win, handler});
|
||||||
|
}
|
||||||
|
|
||||||
|
untrackWindow(windowId) {
|
||||||
|
const entry = this.resizeHandlers.get(windowId);
|
||||||
|
if(entry) {
|
||||||
|
entry.win.removeEventListener("resize", entry.handler);
|
||||||
|
this.resizeHandlers.delete(windowId);
|
||||||
|
}
|
||||||
|
this.clearTiddlers(windowId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tracker = new WindowDimensionsTracker(updateInfoTiddlersCallback);
|
||||||
|
|
||||||
|
// Track main window
|
||||||
|
tracker.trackWindow(window,"system/main");
|
||||||
|
|
||||||
|
// Hook into event bus for user windows
|
||||||
|
if($tw.eventBus) {
|
||||||
|
$tw.eventBus.on("window:opened", ({window: win, windowID}) => {
|
||||||
|
tracker.trackWindow(win, "user/" + windowID);
|
||||||
|
});
|
||||||
|
$tw.eventBus.on("window:closed", ({windowID}) => {
|
||||||
|
tracker.untrackWindow("user/" + windowID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue