mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2026-01-23 11:24:40 +00:00
Compare commits
296 Commits
v5.3.6
...
multi-wiki
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dc2486d4b | ||
|
|
d9256707f4 | ||
|
|
e85cfdefa6 | ||
|
|
dabbc1bacc | ||
|
|
1a1f166ac8 | ||
|
|
f2306a9a2f | ||
|
|
b198270cb5 | ||
|
|
044ce8fbc2 | ||
|
|
36ae2e82be | ||
|
|
1e70e097e7 | ||
|
|
3836a5d08c | ||
|
|
24ada16130 | ||
|
|
d919b825ed | ||
|
|
83f7b9023d | ||
|
|
8151942bd4 | ||
|
|
a02c8e1cc4 | ||
|
|
7f730b7cbf | ||
|
|
9362121e8d | ||
|
|
5ea4077385 | ||
|
|
287d4ff63d | ||
|
|
07c3081e7f | ||
|
|
c0843420d5 | ||
|
|
e3052647ff | ||
|
|
7c4d0d7f5e | ||
|
|
520188dc2b | ||
|
|
aa0d59e4ba | ||
|
|
c1a441b7a1 | ||
|
|
0f558a1442 | ||
|
|
31a7d648e5 | ||
|
|
a6c5b86343 | ||
|
|
ffbf24ae92 | ||
|
|
12e48af372 | ||
|
|
943030ccd2 | ||
|
|
f61a131119 | ||
|
|
8d53a37d34 | ||
|
|
386af03f6d | ||
|
|
8ac2730eb1 | ||
|
|
de9a12b8f9 | ||
|
|
e873518d6f | ||
|
|
316bd65296 | ||
|
|
3a5f67d4f5 | ||
|
|
ad901a9f50 | ||
|
|
c7531e53ab | ||
|
|
6a7612ddf8 | ||
|
|
5d6ddaee7e | ||
|
|
d0575d6e8e | ||
|
|
6dd6b7bef1 | ||
|
|
517dae8242 | ||
|
|
d0b5f413a4 | ||
|
|
6e7efeb126 | ||
|
|
0f4f60f978 | ||
|
|
a9c124cffd | ||
|
|
4050ba5f92 | ||
|
|
b698b3e9cf | ||
|
|
a930411cfd | ||
|
|
90848a1e96 | ||
|
|
c73311684b | ||
|
|
8a5a684218 | ||
|
|
3287dce40c | ||
|
|
eac8a2c3d8 | ||
|
|
535c440741 | ||
|
|
9eb28a0e5f | ||
|
|
edc32c5262 | ||
|
|
6492ed36bf | ||
|
|
2819b53c04 | ||
|
|
adb2ffcd4d | ||
|
|
97db75e741 | ||
|
|
066771e6e9 | ||
|
|
b4664bd7d1 | ||
|
|
882438db14 | ||
|
|
e9f314579d | ||
|
|
9e2962b24e | ||
|
|
5b53a14903 | ||
|
|
39b7a4fb71 | ||
|
|
f1d0e52ff7 | ||
|
|
d1edf6424d | ||
|
|
e9cbb51f68 | ||
|
|
0ff3875b8a | ||
|
|
38e1ea8f90 | ||
|
|
2b2fd4bdb7 | ||
|
|
b8f463d8ba | ||
|
|
3f30cb4991 | ||
|
|
049951e269 | ||
|
|
3c36e4bd55 | ||
|
|
d03ad0bca6 | ||
|
|
109d92ae68 | ||
|
|
e396334b20 | ||
|
|
d8fd9af63a | ||
|
|
9b6d677726 | ||
|
|
a37d50166f | ||
|
|
b4564e31bd | ||
|
|
33fb857d6b | ||
|
|
4c2c7266d7 | ||
|
|
3c7f06009b | ||
|
|
87f4a525f8 | ||
|
|
92a1c56d31 | ||
|
|
d8eb5cb459 | ||
|
|
268aaebaf0 | ||
|
|
ea318bab6e | ||
|
|
aafe775779 | ||
|
|
129bbe421c | ||
|
|
471ba99a5d | ||
|
|
516a17a6f0 | ||
|
|
2e4980bb97 | ||
|
|
db9978f8c2 | ||
|
|
cc4cb04900 | ||
|
|
9ba4556250 | ||
|
|
131a5abeb8 | ||
|
|
ce79a4add8 | ||
|
|
28a831489b | ||
|
|
51cdca6841 | ||
|
|
d51ad80f80 | ||
|
|
ad528d6b1f | ||
|
|
f2947e73b3 | ||
|
|
baee0bb301 | ||
|
|
8a2111f150 | ||
|
|
fcffff3964 | ||
|
|
cca1f21d02 | ||
|
|
37f6930bf2 | ||
|
|
4b1affee50 | ||
|
|
464d17b522 | ||
|
|
d1bb7159b8 | ||
|
|
b58cfe6324 | ||
|
|
7a0c43436f | ||
|
|
708e21951f | ||
|
|
8198574087 | ||
|
|
6c9b92400e | ||
|
|
8091db37e8 | ||
|
|
e66b67dedc | ||
|
|
a2012dcff8 | ||
|
|
08649dd1eb | ||
|
|
52f76380c7 | ||
|
|
1f63bcbbd0 | ||
|
|
3aa5607a3a | ||
|
|
eaebeb87c9 | ||
|
|
808b94468e | ||
|
|
60e6c8bcb2 | ||
|
|
891f0fd599 | ||
|
|
6154de0d2c | ||
|
|
cae9dbf5d1 | ||
|
|
ae8ef305fa | ||
|
|
9b3ca525ee | ||
|
|
38ee942d8f | ||
|
|
957329d515 | ||
|
|
6063256439 | ||
|
|
1c64646393 | ||
|
|
259b3dca1b | ||
|
|
6a673e6aea | ||
|
|
f606e33415 | ||
|
|
09de91940e | ||
|
|
3d485f0706 | ||
|
|
7eaa9b8aec | ||
|
|
faa4b9700a | ||
|
|
dea739ff07 | ||
|
|
69cc45bf5c | ||
|
|
347aa4d546 | ||
|
|
b4855b25c4 | ||
|
|
d518675e03 | ||
|
|
9b59ae2b73 | ||
|
|
f67573315e | ||
|
|
501f57499e | ||
|
|
2916cb6fd9 | ||
|
|
e553539b2a | ||
|
|
3da773c27f | ||
|
|
b923be5e94 | ||
|
|
c9ab184c65 | ||
|
|
bc45a16f40 | ||
|
|
8b6642b56d | ||
|
|
d6807cb471 | ||
|
|
f9064428c5 | ||
|
|
a443e5f0ad | ||
|
|
24413c53dd | ||
|
|
8b5c3746f8 | ||
|
|
9df625c44d | ||
|
|
54ff0446c6 | ||
|
|
0f5dfb89ad | ||
|
|
e3b27768d2 | ||
|
|
580283433e | ||
|
|
f4ac2b92e7 | ||
|
|
e35584843d | ||
|
|
3335e87ef4 | ||
|
|
abde67e5df | ||
|
|
2ba3643a0c | ||
|
|
89ae2012c7 | ||
|
|
8a209d643f | ||
|
|
1a28ec7ea4 | ||
|
|
5fe41fc896 | ||
|
|
4f9ff1ae81 | ||
|
|
d97ddf1eec | ||
|
|
9facf4a067 | ||
|
|
de4fe132a7 | ||
|
|
d7d0733177 | ||
|
|
e614e291a2 | ||
|
|
dd9a3bfeeb | ||
|
|
83229ace63 | ||
|
|
6724fa804b | ||
|
|
630b98520f | ||
|
|
1c0341de51 | ||
|
|
d5aa74d9af | ||
|
|
343cc33bbe | ||
|
|
b1edbed6a5 | ||
|
|
066e553f84 | ||
|
|
61b54125be | ||
|
|
3276703edd | ||
|
|
f9265169fd | ||
|
|
2361880c45 | ||
|
|
3ad87df154 | ||
|
|
3c58788e37 | ||
|
|
310b5f058a | ||
|
|
a33705e348 | ||
|
|
3fca82321e | ||
|
|
790f431df0 | ||
|
|
0d22bf8418 | ||
|
|
1eecfb6b3a | ||
|
|
b8c1c6c8de | ||
|
|
6503fb4a04 | ||
|
|
bab14b7053 | ||
|
|
2d4b3341f6 | ||
|
|
6f8a3b9261 | ||
|
|
8edefffbc5 | ||
|
|
59b425fd5c | ||
|
|
f2267e2af0 | ||
|
|
c26acfdb42 | ||
|
|
f925f036c9 | ||
|
|
2c810faeeb | ||
|
|
6675358e85 | ||
|
|
262a730534 | ||
|
|
4b6872aa42 | ||
|
|
3283d38867 | ||
|
|
4204ff367e | ||
|
|
51e646690c | ||
|
|
85607f7846 | ||
|
|
41a5bcc3a1 | ||
|
|
84c8a9be9b | ||
|
|
62b2fe3e2f | ||
|
|
f5fdd79c7f | ||
|
|
14752ccb0c | ||
|
|
541c166863 | ||
|
|
270f62bbb2 | ||
|
|
8290d853c9 | ||
|
|
b0a67300cc | ||
|
|
0b9749f3a4 | ||
|
|
3ad3e19392 | ||
|
|
ed71adac7e | ||
|
|
8d95c92bfb | ||
|
|
41ab94978f | ||
|
|
26e198b7d8 | ||
|
|
d16746ab38 | ||
|
|
627c3e20cc | ||
|
|
4d42d4a190 | ||
|
|
ff184822ca | ||
|
|
ddbd6d1e82 | ||
|
|
f6d6478944 | ||
|
|
138c7f2665 | ||
|
|
239ace0c07 | ||
|
|
c1312100aa | ||
|
|
e343eccdc3 | ||
|
|
da5b316358 | ||
|
|
dc8692044c | ||
|
|
4f9ba11489 | ||
|
|
f7914db019 | ||
|
|
11ecaff7db | ||
|
|
d832bbcc70 | ||
|
|
59aed49e98 | ||
|
|
e9f83ca735 | ||
|
|
afa9ad3cde | ||
|
|
01d29ed11e | ||
|
|
8f9ae7e4d5 | ||
|
|
70b048f356 | ||
|
|
5fddd3b104 | ||
|
|
02afbb4000 | ||
|
|
54432485e7 | ||
|
|
26ede2839b | ||
|
|
4b0df1a7ae | ||
|
|
9767e7d3b7 | ||
|
|
4133e7d6d6 | ||
|
|
4f37355a9f | ||
|
|
82fae45656 | ||
|
|
2f09c32d2d | ||
|
|
a16338ce11 | ||
|
|
50d0b1412d | ||
|
|
8941bd1747 | ||
|
|
615dc0c4a3 | ||
|
|
1fb8b2e279 | ||
|
|
0799177cf4 | ||
|
|
1eed61397b | ||
|
|
3f1f7c7ef7 | ||
|
|
8543dda4aa | ||
|
|
68a89b615d | ||
|
|
e9d3f67c5c | ||
|
|
a980390870 | ||
|
|
299781bdba | ||
|
|
f42d3e0536 | ||
|
|
993eb5c90d | ||
|
|
f8f8319324 | ||
|
|
12d84c43c9 |
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
branches:
|
||||
- master
|
||||
- tiddlywiki-com
|
||||
- multi-wiki-support
|
||||
env:
|
||||
NODE_VERSION: "22"
|
||||
jobs:
|
||||
@@ -82,3 +83,14 @@ jobs:
|
||||
- run: "./bin/build-tw-org.sh"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUBPUSHTOKEN }}
|
||||
build-mws-tiddlywiki-com:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.ref == 'refs/heads/multi-wiki-support'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: "${{ env.NODE_VERSION }}"
|
||||
- run: "./bin/build-mws-site.sh"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUBPUSHTOKEN }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,7 +5,9 @@
|
||||
tmp/
|
||||
output/
|
||||
node_modules/
|
||||
store/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
$__StoryList.tid
|
||||
/editions/test/test-store/*
|
||||
4
TODO BEFORE MERGING THIS PR.md
Normal file
4
TODO BEFORE MERGING THIS PR.md
Normal file
@@ -0,0 +1,4 @@
|
||||
The `multi-wiki-support` branch includes some changes that are not intended to be merged into the `master` branch:
|
||||
|
||||
* Readme update (see `editions/tw5.com/tiddlers/readme/ReadMe.tid`)
|
||||
* Remove `multiwikiserver` plugin from `readme-bld.sh` (see `bin/readme-bld.sh`)
|
||||
97
bin/build-mws-site.sh
Executable file
97
bin/build-mws-site.sh
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Build mws.tiddlywiki.com assets.
|
||||
|
||||
# Default to the version of TiddlyWiki installed in this repo
|
||||
|
||||
if [ -z "$MWSTWCOM_BUILD_TIDDLYWIKI" ]; then
|
||||
MWSTWCOM_BUILD_TIDDLYWIKI=./tiddlywiki.js
|
||||
fi
|
||||
|
||||
echo "Using MWSTWCOM_BUILD_TIDDLYWIKI as [$MWSTWCOM_BUILD_TIDDLYWIKI]"
|
||||
|
||||
# Set up the build details
|
||||
|
||||
if [ -z "$MWSTWCOM_BUILD_DETAILS" ]; then
|
||||
MWSTWCOM_BUILD_DETAILS="$(git symbolic-ref --short HEAD)-$(git rev-parse HEAD) from $(git remote get-url origin)"
|
||||
fi
|
||||
|
||||
echo "Using MWSTWCOM_BUILD_DETAILS as [$MWSTWCOM_BUILD_DETAILS]"
|
||||
|
||||
if [ -z "$MWSTWCOM_BUILD_COMMIT" ]; then
|
||||
MWSTWCOM_BUILD_COMMIT="$(git rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
echo "Using MWSTWCOM_BUILD_COMMIT as [$MWSTWCOM_BUILD_COMMIT]"
|
||||
|
||||
# Set up the build output directory
|
||||
|
||||
if [ -z "$MWSTWCOM_BUILD_OUTPUT" ]; then
|
||||
MWSTWCOM_BUILD_OUTPUT=$(mktemp -d)
|
||||
fi
|
||||
|
||||
mkdir -p $MWSTWCOM_BUILD_OUTPUT
|
||||
|
||||
if [ ! -d "$MWSTWCOM_BUILD_OUTPUT" ]; then
|
||||
echo 'A valid MWSTWCOM_BUILD_OUTPUT environment variable must be set'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using MWSTWCOM_BUILD_OUTPUT as [$MWSTWCOM_BUILD_OUTPUT]"
|
||||
|
||||
# Pull existing GitHub pages content
|
||||
|
||||
git clone --depth=1 --branch=main "https://github.com/TiddlyWiki/mws.tiddlywiki.com-gh-pages.git" $MWSTWCOM_BUILD_OUTPUT
|
||||
|
||||
# Make the CNAME file that GitHub Pages requires
|
||||
|
||||
echo "mws.tiddlywiki.com" > $MWSTWCOM_BUILD_OUTPUT/CNAME
|
||||
|
||||
# Delete any existing static content
|
||||
|
||||
mkdir -p $MWSTWCOM_BUILD_OUTPUT/static
|
||||
rm $MWSTWCOM_BUILD_OUTPUT/static/*
|
||||
|
||||
# Put the build details into a .tid file so that it can be included in each build (deleted at the end of this script)
|
||||
|
||||
echo -e -n "title: $:/build\ncommit: $MWSTWCOM_BUILD_COMMIT\n\n$MWSTWCOM_BUILD_DETAILS\n" > $MWSTWCOM_BUILD_OUTPUT/build.tid
|
||||
|
||||
######################################################
|
||||
#
|
||||
# mws.tiddlywiki.com distribution
|
||||
#
|
||||
######################################################
|
||||
|
||||
# /index.html Main site
|
||||
# /favicon.ico Favicon for main site
|
||||
# /static.html Static rendering of default tiddlers
|
||||
# /alltiddlers.html Static rendering of all tiddlers
|
||||
# /static/* Static single tiddlers
|
||||
# /static/static.css Static stylesheet
|
||||
# /static/favicon.ico Favicon for static pages
|
||||
node $MWSTWCOM_BUILD_TIDDLYWIKI \
|
||||
editions/multiwikidocs \
|
||||
--verbose \
|
||||
--version \
|
||||
--load $MWSTWCOM_BUILD_OUTPUT/build.tid \
|
||||
--output $MWSTWCOM_BUILD_OUTPUT \
|
||||
--build favicon static index \
|
||||
|| exit 1
|
||||
|
||||
# Delete the temporary build tiddler
|
||||
|
||||
rm $MWSTWCOM_BUILD_OUTPUT/build.tid || exit 1
|
||||
|
||||
# Push output back to GitHub
|
||||
|
||||
# Exit script immediately if any command fails
|
||||
set -e
|
||||
|
||||
pushd $MWSTWCOM_BUILD_OUTPUT
|
||||
git config --global user.email "actions@github.com"
|
||||
git config --global user.name "GitHub Actions"
|
||||
git add -A .
|
||||
git commit --message "GitHub build: $GITHUB_RUN_NUMBER of $TW5_BUILD_BRANCH ($(date +'%F %T %Z'))"
|
||||
git remote add deploy "https://$GH_TOKEN@github.com/TiddlyWiki/mws.tiddlywiki.com-gh-pages.git" &>/dev/null
|
||||
git push deploy main &>/dev/null
|
||||
popd
|
||||
@@ -5,7 +5,7 @@
|
||||
# Default to the current version number for building the plugin library
|
||||
|
||||
if [ -z "$TW5_BUILD_VERSION" ]; then
|
||||
TW5_BUILD_VERSION=v5.3.6
|
||||
TW5_BUILD_VERSION=v5.3.7
|
||||
fi
|
||||
|
||||
echo "Using TW5_BUILD_VERSION as [$TW5_BUILD_VERSION]"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
# test TiddlyWiki5 for tiddlywiki.com
|
||||
|
||||
npm install
|
||||
|
||||
node ./tiddlywiki.js \
|
||||
./editions/test \
|
||||
--verbose \
|
||||
|
||||
@@ -10,6 +10,7 @@ fi
|
||||
|
||||
# tw5.com readmes
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
+plugins/tiddlywiki/multiwikiserver \
|
||||
editions/tw5.com \
|
||||
--verbose \
|
||||
--output . \
|
||||
|
||||
@@ -38,6 +38,13 @@ Commander.prototype.log = function(str) {
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Clear pending commands
|
||||
*/
|
||||
Commander.prototype.clearCommands = function() {
|
||||
this.commandTokens = this.commandTokens.slice(0,this.nextToken);
|
||||
};
|
||||
|
||||
/*
|
||||
Write a string if verbose flag is set
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@ var Server = require("$:/core/modules/server/server.js").Server;
|
||||
|
||||
exports.info = {
|
||||
name: "listen",
|
||||
synchronous: true,
|
||||
synchronous: false,
|
||||
namedParameterMode: true,
|
||||
mandatoryParameters: []
|
||||
};
|
||||
@@ -38,7 +38,11 @@ Command.prototype.execute = function() {
|
||||
wiki: this.commander.wiki,
|
||||
variables: self.params
|
||||
});
|
||||
var nodeServer = this.server.listen();
|
||||
var nodeServer = this.server.listen(null,null,null,{
|
||||
callback: function() {
|
||||
self.callback();
|
||||
}
|
||||
});
|
||||
$tw.hooks.invokeHook("th-server-command-post-start",this.server,nodeServer,"tiddlywiki");
|
||||
return null;
|
||||
};
|
||||
|
||||
37
core/modules/commands/quit.js
Normal file
37
core/modules/commands/quit.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*\
|
||||
title: $:/core/modules/commands/quit.js
|
||||
type: application/javascript
|
||||
module-type: command
|
||||
|
||||
Immediately ends the TiddlyWiki process
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.info = {
|
||||
name: "quit",
|
||||
synchronous: true
|
||||
};
|
||||
|
||||
var Command = function(params,commander,callback) {
|
||||
var self = this;
|
||||
this.params = params;
|
||||
this.commander = commander;
|
||||
this.callback = callback;
|
||||
};
|
||||
|
||||
Command.prototype.execute = function() {
|
||||
// Clear any pending commands
|
||||
this.commander.clearCommands();
|
||||
// We don't actually quit, we just issue the "th-quit" hook to give listeners a chance to exit
|
||||
$tw.hooks.invokeHook("th-quit");
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.Command = Command;
|
||||
|
||||
})();
|
||||
@@ -364,6 +364,11 @@ Server.prototype.listen = function(port,host,prefix) {
|
||||
}
|
||||
// Display the port number after we've started listening (the port number might have been specified as zero, in which case we will get an assigned port)
|
||||
server.on("listening",function() {
|
||||
// Stop listening when we get the "th-quit" hook
|
||||
$tw.hooks.addHook("th-quit",function() {
|
||||
server.close();
|
||||
});
|
||||
// Log listening details
|
||||
var address = server.address(),
|
||||
url = self.protocol + "://" + (address.family === "IPv6" ? "[" + address.address + "]" : address.address) + ":" + address.port + prefix;
|
||||
$tw.utils.log("Serving on " + url,"brown/orange");
|
||||
|
||||
@@ -257,7 +257,11 @@ Save an incoming tiddler in the store, and updates the associated tiddlerInfo
|
||||
Syncer.prototype.storeTiddler = function(tiddlerFields) {
|
||||
// Save the tiddler
|
||||
var tiddler = new $tw.Tiddler(tiddlerFields);
|
||||
this.wiki.addTiddler(tiddler);
|
||||
// Only save the tiddler if it has changed
|
||||
var existingTiddler = this.wiki.getTiddler(tiddlerFields.title);
|
||||
if(!existingTiddler || !existingTiddler.isEqual(tiddler)) {
|
||||
this.wiki.addTiddler(tiddler);
|
||||
}
|
||||
// Save the tiddler revision and changeCount details
|
||||
this.tiddlerInfo[tiddlerFields.title] = {
|
||||
revision: this.getTiddlerRevision(tiddlerFields.title),
|
||||
@@ -556,6 +560,7 @@ SaveTiddlerTask.prototype.run = function(callback) {
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
syncer: self.syncer,
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[self.title]
|
||||
});
|
||||
} else {
|
||||
@@ -586,6 +591,7 @@ DeleteTiddlerTask.prototype.run = function(callback) {
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
syncer: self.syncer,
|
||||
tiddlerInfo: self.syncer.tiddlerInfo[this.title]
|
||||
});
|
||||
};
|
||||
@@ -614,6 +620,8 @@ LoadTiddlerTask.prototype.run = function(callback) {
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null);
|
||||
},{
|
||||
syncer: self.syncer
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -163,4 +163,4 @@ ImageWidget.prototype.refresh = function(changedTiddlers) {
|
||||
|
||||
exports.image = ImageWidget;
|
||||
|
||||
})();
|
||||
})();
|
||||
@@ -44,7 +44,8 @@ NavigatorWidget.prototype.render = function(parent,nextSibling) {
|
||||
{type: "tm-fold-tiddler", handler: "handleFoldTiddlerEvent"},
|
||||
{type: "tm-fold-other-tiddlers", handler: "handleFoldOtherTiddlersEvent"},
|
||||
{type: "tm-fold-all-tiddlers", handler: "handleFoldAllTiddlersEvent"},
|
||||
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"}
|
||||
{type: "tm-unfold-all-tiddlers", handler: "handleUnfoldAllTiddlersEvent"},
|
||||
{type: "tm-manage-acl", handler: "handleManageACLTiddlersEvent"}
|
||||
]);
|
||||
this.parentDomNode = parent;
|
||||
this.computeAttributes();
|
||||
@@ -635,6 +636,14 @@ NavigatorWidget.prototype.handleUnfoldAllTiddlersEvent = function(event) {
|
||||
});
|
||||
};
|
||||
|
||||
NavigatorWidget.prototype.handleManageACLTiddlersEvent = function() {
|
||||
var pathname = window.location.pathname;
|
||||
var paths = pathname.split("/");
|
||||
var recipeName = paths[paths.length - 1];
|
||||
var bagName = document.querySelector("h1.tc-site-title").innerHTML;
|
||||
window.location.href = "/admin/acl/"+recipeName+"/"+bagName
|
||||
};
|
||||
|
||||
exports.navigator = NavigatorWidget;
|
||||
|
||||
})();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.3.6/index.html
|
||||
url: https://tiddlywiki.com/library/v5.3.7/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
|
||||
{{$:/language/OfficialPluginLibrary/Hint}}
|
||||
|
||||
41
editions/multiwikidocs/tiddlers/Bags and Recipes.tid
Normal file
41
editions/multiwikidocs/tiddlers/Bags and Recipes.tid
Normal file
@@ -0,0 +1,41 @@
|
||||
created: 20240309135835396
|
||||
modified: 20240309142156125
|
||||
title: Bags and Recipes
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
The bags and recipes model is a reference architecture for how tiddlers can be shared between multiple wikis. It was first introduced by TiddlyWeb in 2008.
|
||||
|
||||
The principles of bags and recipes can be simply stated:
|
||||
|
||||
# Tiddlers are stored in named "bags"
|
||||
# Bags have access controls that determines which users can read or write to them
|
||||
# Recipes are named lists of bags, ordered from lowest priority to highest
|
||||
# The tiddlers within a recipe are accumulated in turn from each bag in the recipe in order of increasing priority. Thus, if there are multiple tiddlers with the same title in different bags then the one from the highest priority bag will be used as the recipe tiddler
|
||||
# Wikis are composed by splicing the tiddlers from the corresponding recipe into the standard TW5 HTML template
|
||||
|
||||
A very simple example of the recipe/bag model might be for a single user who maintains the following bags:
|
||||
|
||||
* ''recipes'' - tiddlers related to cooking recipes
|
||||
* ''work'' - tiddlers related to work
|
||||
* ''app'' - common tiddlers for customising TiddlyWiki
|
||||
|
||||
Those bags would be used with the following recipes:
|
||||
|
||||
* ''recipes'' --> recipes, app - wiki for working with recipes, with common custom components
|
||||
* ''work'' --> work, app - wiki for working with work, with common custom components
|
||||
* ''app'' --> app - wiki for maintaining custom components
|
||||
|
||||
All of this will work dynamically, so changes to the app bag will instantly ripple into the affected hosted wikis.
|
||||
|
||||
A more complex example might be for a teacher working with a group of students:
|
||||
|
||||
* ''student-{name}'' bag for each students work
|
||||
* ''teacher-course'' bag for the coursework, editable by the teacher
|
||||
* ''teacher-tools'' bag for custom tools used by the teacher
|
||||
|
||||
Those bags would be exposed through the following hosted wikis:
|
||||
|
||||
* ''student-{name}'' hosted wiki for each students work, including the coursework material
|
||||
* ''teacher-course'' hosted wiki for the coursework, editable by the teacher
|
||||
* ''teacher'' hosted wiki for the teacher, bringing together all the bags, giving them an overview of all the students work
|
||||
|
||||
15
editions/multiwikidocs/tiddlers/Database Engines.tid
Normal file
15
editions/multiwikidocs/tiddlers/Database Engines.tid
Normal file
@@ -0,0 +1,15 @@
|
||||
title: Database Engines
|
||||
tags: Reference
|
||||
|
||||
MWS uses [[SQLite]] for data storage. It supports choosing between two "database engines" that are based on two different npm modules:
|
||||
|
||||
* [[better-sqlite3|https://www.npmjs.com/package/better-sqlite3]] is written partially in C/C++ and so requires compilation for the target platform
|
||||
* [[node-sqlite3-wasm|https://www.npmjs.com/package/node-sqlite3-wasm]] is written entirely in JavaScript and does not require compilation, but does require a WebAssembly-capable Node.js host. This is not currently possible on some platforms such as iOS/iPadOS
|
||||
|
||||
By default `npm install` will install both database engines. By default it will use `better-sqlite3`. To switch to using `node-sqlite3-wasm`, set the system configuration tiddler `$:/config/MultiWikiServer/Engine` to `wasm` (the default value is `better`). Note that this tiddler resides in the [[Administration Wiki]].
|
||||
|
||||
!! Avoiding Installation Errors
|
||||
|
||||
If you encounter errors during `npm install` related to `gyp` or `prebuild`, you may be able to avoid them by using `node-sqlite3-wasm` instead of `better-sqlite3`. However, it will be necessary to manually install `node-sqlite3-wasm` and its dependencies. This can be done by running the following commands in your terminal:
|
||||
|
||||
<<.copy-code-to-clipboard "npm install node-sqlite3-wasm">>
|
||||
6
editions/multiwikidocs/tiddlers/DefaultTiddlers.tid
Normal file
6
editions/multiwikidocs/tiddlers/DefaultTiddlers.tid
Normal file
@@ -0,0 +1,6 @@
|
||||
title: $:/DefaultTiddlers
|
||||
|
||||
HelloThere
|
||||
Installation
|
||||
Usage
|
||||
Reference
|
||||
17
editions/multiwikidocs/tiddlers/HelloThere.tid
Normal file
17
editions/multiwikidocs/tiddlers/HelloThere.tid
Normal file
@@ -0,0 +1,17 @@
|
||||
title: HelloThere
|
||||
tags: TableOfContents
|
||||
|
||||
!! ~TiddlyWiki is Growing Up
|
||||
|
||||
<span class="tc-float-right">[img width=200 [MWS Banner.png]]</span>
|
||||
~MultiWikiServer is a new development that drastically improves ~TiddlyWiki's capabilities when running as a server under Node.js. It brings ~TiddlyWiki up to par with common web-based tools like ~WordPress or ~MediaWiki by supporting multiple wikis and multiple users at the same time.
|
||||
|
||||
Planned features include:
|
||||
|
||||
* Hosting multiple wikis at once, using the [[Bags and Recipes]] mechanism for sharing data between them
|
||||
* Robust authentication and authorisation options
|
||||
* Improved handling of file uploads and attachments, allowing gigabyte video files to be uploaded and streamed
|
||||
* Instantaneous synchronisation of changes between the server and all connected clients
|
||||
* Workflow processing on the server, for example to automatically compress images, or to archive webpages
|
||||
|
||||
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/TiddlyWiki5/pull/7915]] but it is already functional and usable.
|
||||
@@ -1,17 +1,19 @@
|
||||
title: MWS: Installation using Git
|
||||
tags: MultiWikiServer
|
||||
title: Installation using Git
|
||||
tags: Installation
|
||||
modified: 20241105133737778
|
||||
created: 20241105133737778
|
||||
|
||||
These instructions require basic knowledge both of the terminal and of Git. There are also [[alternative instructions without using Git|MWS: Installation]].
|
||||
These instructions require basic knowledge both of the terminal and of Git. There are also [[alternative instructions without using Git|Installation]].
|
||||
|
||||
# Clone the code from GitHub with: <<.copy-code-to-clipboard "git clone -b multi-wiki-support --single-branch https://github.com/TiddlyWiki/TiddlyWiki5">>
|
||||
# Open a terminal window in the root of the downloaded folder
|
||||
# Open a terminal window and set the current directory to the root of the downloaded folder
|
||||
# Install the dependencies with the command: <<.copy-code-to-clipboard "npm install">>
|
||||
# Start the server with the command: <<.copy-code-to-clipboard "npm start">>
|
||||
# To use MWS, visit http://localhost:8080 in a browser on the same computer
|
||||
# When you have finished using MWS, stop the server with <kbd>ctrl-C</kbd>
|
||||
|
||||
See [[Troubleshooting]] if you encounter any errors.
|
||||
|
||||
To update your copy of MWS with newer changes from ~GitHub, run the following command:
|
||||
|
||||
<<.copy-code-to-clipboard "git pull">>
|
||||
@@ -1,15 +1,17 @@
|
||||
title: MWS: Installation
|
||||
tags: MultiWikiServer
|
||||
title: Installation
|
||||
tags: TableOfContents
|
||||
modified: 20241105133737778
|
||||
created: 20241105133737778
|
||||
|
||||
These instructions require minimal knowledge of the terminal. There are also [[alternative instructions for those using Git|MWS: Installation using Git]].
|
||||
These instructions require minimal knowledge of the terminal. There are also [[alternative instructions for those using Git|Installation using Git]].
|
||||
|
||||
# Download the code [[direct from GitHub|https://github.com/TiddlyWiki/TiddlyWiki5/archive/refs/pull/7915/head.zip]]
|
||||
# Open a terminal window in the root of the downloaded folder
|
||||
# Open a terminal window and set the current directory to the root of the downloaded folder
|
||||
# Install the dependencies with the command: <<.copy-code-to-clipboard "npm install">>
|
||||
# Start the server with the command: <<.copy-code-to-clipboard "npm start">>
|
||||
# To use MWS, visit http://localhost:8080 in a browser on the same computer
|
||||
# When you have finished using MWS, stop the server with <kbd>ctrl-C</kbd>
|
||||
|
||||
To update your copy of MWS with newer changes will require re-downloading the code, taking care not to lose any changes you might have made.
|
||||
See [[Troubleshooting]] if you encounter any errors.
|
||||
|
||||
To update your copy of MWS in the future with newer changes will require re-downloading the code, taking care not to lose any changes you might have made.
|
||||
230
editions/multiwikidocs/tiddlers/Reference.tid
Normal file
230
editions/multiwikidocs/tiddlers/Reference.tid
Normal file
@@ -0,0 +1,230 @@
|
||||
title: Reference
|
||||
tags: TableOfContents
|
||||
|
||||
! Authentication & Authorization
|
||||
|
||||
!! Overview
|
||||
|
||||
Our application has transitioned from a conventional username/password authentication system to a more robust Authentication and Authorization implementation. This new system supports multiple user accounts, roles, permissions, and a comprehensive access control list.
|
||||
|
||||
!! Key Features
|
||||
|
||||
# Multiple User Accounts
|
||||
# Role-based Access Control
|
||||
# Granular Permissions
|
||||
# Access Control List (ACL)
|
||||
|
||||
!! Application Access & Security
|
||||
|
||||
!!! Initial Setup
|
||||
When you first launch the Multiwiki Server, it operates in an unauthenticated mode to facilitate initial configuration. During this initial state, the system creates a temporary anonymous administrator account. Upon accessing the landing page, you'll receive a prominent security warning with instructions to establish a permanent ADMIN account. It's crucial to create this account immediately to secure your installation.
|
||||
|
||||
!!! User Types and Permissions
|
||||
|
||||
!!!! Administrator (ADMIN)
|
||||
|
||||
* Full system access and configuration rights
|
||||
* Can create, modify, and delete user accounts
|
||||
* Manages role assignments and permissions
|
||||
* Controls global system settings
|
||||
* Can configure guest access policies
|
||||
* Has complete control over all recipes and tiddlers
|
||||
|
||||
!!!! Regular Users
|
||||
* Custom accounts created by administrators
|
||||
* Permissions determined by assigned roles
|
||||
* Access limited to specific recipes based on role permissions
|
||||
* Can have READ and/or WRITE permissions
|
||||
|
||||
!!!! Guest Users
|
||||
* Default anonymous access level
|
||||
* No inherent permissions
|
||||
* Can only access recipes without Access Control Lists (ACLs)
|
||||
* Read/write capabilities configurable by ADMIN
|
||||
* Useful for public wikis or documentation sites
|
||||
|
||||
!!! Access Control System
|
||||
|
||||
!!!! Recipe-Level Security
|
||||
* Access control is implemented at the recipe level
|
||||
* Each recipe can have its own Access Control List (ACL)
|
||||
* Permissions are granular:
|
||||
** READ: Allows viewing recipe contents
|
||||
** WRITE: Allows modifications to recipe contents
|
||||
|
||||
!!!! Role-Based Access Control (RBAC)
|
||||
* Administrators can create custom roles
|
||||
* Roles can be assigned specific READ/WRITE permissions
|
||||
* Users inherit permissions from their assigned roles
|
||||
* Multiple roles can be assigned to a single user
|
||||
* Provides flexible and scalable access management
|
||||
|
||||
!!!! Permission Inheritance
|
||||
* Users receive combined permissions from all assigned roles
|
||||
* More permissive role takes precedence in conflicts
|
||||
* Guest access is overridden by recipe ACLs
|
||||
* System automatically enforces most restrictive access when conflicts occur
|
||||
|
||||
This security model allows for fine-grained control over content access while maintaining flexibility for both private and public wiki deployments.
|
||||
|
||||
!! User Management & Security Architecture
|
||||
|
||||
!!! User Account Management
|
||||
|
||||
Users can be administered through two interfaces:
|
||||
|
||||
# Web-based Administrative Interface
|
||||
#* Accessible only to ADMIN users
|
||||
#* Provides graphical interface for user operations
|
||||
#* Real-time validation and feedback
|
||||
# Command-line Interface (CLI) Tools
|
||||
#* Suitable for automation and scripting
|
||||
#* Enables batch operations
|
||||
#* Useful for system initialization
|
||||
|
||||
Each user account contains the following essential components:
|
||||
|
||||
* ''Username''
|
||||
** Must be unique across the system
|
||||
** Case-sensitive
|
||||
** Used for authentication and audit trails
|
||||
* ''Password''
|
||||
** Stored using secure hashing algorithms
|
||||
** Never stored in plaintext
|
||||
** Subject to complexity requirements
|
||||
* ''Role Assignments''
|
||||
** Multiple roles can be assigned
|
||||
** Inherited permissions from all assigned roles
|
||||
** Dynamic permission calculation based on role combination
|
||||
|
||||
!!! Role & Permission Framework
|
||||
|
||||
!!!! Role Management
|
||||
|
||||
Roles serve as permission containers and provide organized access control. The system includes:
|
||||
|
||||
Built-in Roles:
|
||||
|
||||
* `ADMIN`
|
||||
** Highest privilege level
|
||||
** Full system access
|
||||
** Cannot be modified or deleted
|
||||
** Can create and manage other roles
|
||||
** Controls guest access policies
|
||||
|
||||
* `USER`
|
||||
** Basic access rights
|
||||
** Typically limited to specific recipes
|
||||
|
||||
**Custom Roles (Examples):**
|
||||
|
||||
* `MANAGER`
|
||||
** Intermediate access level
|
||||
** Can manage subset of resources
|
||||
** Custom roles as needed for specific use cases
|
||||
|
||||
!!!! Permission Architecture
|
||||
|
||||
Core Permissions:
|
||||
|
||||
* `READ` Permission
|
||||
** View recipe contents
|
||||
** Access tiddler data
|
||||
** View metadata
|
||||
** Export capabilities
|
||||
|
||||
* `WRITE` Permission
|
||||
** Create new tiddlers
|
||||
** Modify existing content
|
||||
** Delete resources
|
||||
** Manage recipe contents
|
||||
|
||||
**Guest Access:**
|
||||
|
||||
* No default permissions
|
||||
* Access limited to non-ACL recipes
|
||||
* Configurable by ADMIN users
|
||||
* Suitable for public wikis
|
||||
|
||||
!!! Access Control List (ACL) Implementation
|
||||
|
||||
The ACL system provides granular security control through:
|
||||
|
||||
!!!! Entity-Level Control
|
||||
|
||||
* Recipe-based access control
|
||||
* Individual resource protection
|
||||
* Hierarchical permission inheritance
|
||||
|
||||
!!! Authentication Process Flow
|
||||
|
||||
* Initial Authentication
|
||||
** User submits credentials
|
||||
** System validates username existence
|
||||
** Password hash comparison
|
||||
** Session token generation
|
||||
|
||||
* Session Management
|
||||
** Secure session storage
|
||||
** Token-based authentication
|
||||
** Automatic session expiration
|
||||
** Re-authentication requirements
|
||||
|
||||
!!! Authorization Workflow
|
||||
|
||||
* Request Processing
|
||||
** Capture user action request
|
||||
** Identify target resource
|
||||
** Extract required permissions
|
||||
|
||||
* Permission Validation
|
||||
** Check user roles
|
||||
** Aggregate permissions
|
||||
** Verify ACL entries
|
||||
** Apply guest policies if applicable
|
||||
|
||||
* Access Decision
|
||||
** Compare required vs. available permissions
|
||||
** Apply most restrictive policy
|
||||
** Return access decision
|
||||
|
||||
!!! System Extension Guidelines
|
||||
|
||||
!!!! Adding New Roles
|
||||
|
||||
# Access administrative interface
|
||||
# Define role identifier
|
||||
# Assign base permissions
|
||||
# Configure ACL mappings
|
||||
# Test role functionality
|
||||
|
||||
!!!! Permission Expansion
|
||||
|
||||
# Define new permission type
|
||||
# Update ACL structure
|
||||
# Implement permission checks
|
||||
# Update validation logic
|
||||
# Document new permission
|
||||
|
||||
!!!! Security Considerations
|
||||
|
||||
* Regular permission audits
|
||||
* Role assignment reviews
|
||||
* Guest access monitoring
|
||||
* Security log analysis
|
||||
* Access pattern monitoring
|
||||
|
||||
This comprehensive security model provides flexible, maintainable, and secure access control while supporting both authenticated and guest users within the Multiwiki Server environment.
|
||||
|
||||
! HTTP API
|
||||
|
||||
The ~MultiWikiServer HTTP API provides access to resources hosted by the MWS store. It is based on [[the API of TiddlyWeb|https://tank.peermore.com/tanks/tiddlyweb/HTTP%20API]], first developed in 2008 by Chris Dent.
|
||||
|
||||
The design goals of the API are:
|
||||
|
||||
* To follow the principles of REST where practical
|
||||
* To present resources as nouns, not verbs
|
||||
|
||||
General points about the design:
|
||||
|
||||
* In MWS there are no resources that end with / (except for the root path which is /)
|
||||
@@ -0,0 +1,19 @@
|
||||
title: Troublesheeting gyp/prebuild Installation Errors
|
||||
tags: Troubleshooting
|
||||
modified: 20241105133737778
|
||||
created: 20241105133737778
|
||||
|
||||
Installation may fail with errors related to `gyp` or `prebuild`. These errors are caused by missing dependencies or incorrect versions of dependencies.
|
||||
|
||||
Note that in most cases, these errors occur because of the use of the npm module [[better-sqlite3|https://www.npmjs.com/package/better-sqlite3]]. This module is mostly written in C, and thus requires compilation for the target platform. MWS supports switchable database engines, and also supports the use of the [[node-sqlite3-wasm|https://www.npmjs.com/package/node-sqlite3-wasm]] module which is written in ~JavaScript and does not require compilation and so may avoid these errors. See [[Database Engines]] for more details of how to switch between engines.
|
||||
|
||||
The following steps may help resolve errors involving `gyp` or `prebuild`:
|
||||
|
||||
# Ensure that you have the latest version of Node.js installed. You can download the latest version from the [[Node.js website|https://nodejs.org/]].
|
||||
# Update npm to the latest version by running the following command in your terminal: <<.copy-code-to-clipboard "npm install -g npm@latest">>
|
||||
# Clear the npm cache by running the following command in your terminal: <<.copy-code-to-clipboard "npm cache clean --force">>
|
||||
# Delete the `node_modules` folder in your TiddlyWiki directory by running the following command in your terminal: <<.copy-code-to-clipboard "rm -rf node_modules">>
|
||||
# Reinstall the dependencies by running the following command in your terminal: <<.copy-code-to-clipboard "npm install">>
|
||||
# If you continue to encounter errors, try running the following command in your terminal: <<.copy-code-to-clipboard "npm rebuild">>
|
||||
# If you are still experiencing issues, you may need to manually install the `gyp` and `prebuild` dependencies. You can do this by running the following commands in your terminal: <<.copy-code-to-clipboard "npm install -g node-gyp">> <<.copy-code-to-clipboard "npm install -g prebuild">>
|
||||
# Once you have installed the dependencies, try reinstalling the TiddlyWiki dependencies by running the following command in your terminal: <<.copy-code-to-clipboard "npm install">>
|
||||
4
editions/multiwikidocs/tiddlers/Troubleshooting.tid
Normal file
4
editions/multiwikidocs/tiddlers/Troubleshooting.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: Troubleshooting
|
||||
tags: TableOfContents
|
||||
|
||||
<<list-links "[tag[Troubleshooting]]">>
|
||||
@@ -1,9 +1,9 @@
|
||||
title: MWS: Usage
|
||||
tags: MultiWikiServer
|
||||
title: Usage
|
||||
tags: TableOfContents
|
||||
modified: 20241105133737778
|
||||
created: 20241105133737778
|
||||
|
||||
Once MWS is successfully [[installed|MWS: Installation]], you can access it by visiting http://localhost:8080 in a browser on the same computer.
|
||||
Once MWS is successfully [[installed|Installation]], you can access it by visiting http://localhost:8080 in a browser on the same computer.
|
||||
|
||||
By default, MWS is installed with full anonymous access enabled, meaning that anyone with access to the server has full access to read and modify anything. However, also by default, the server is only accessible to browsers on the same machine.
|
||||
|
||||
BIN
editions/multiwikidocs/tiddlers/images/MWS Banner.png
Normal file
BIN
editions/multiwikidocs/tiddlers/images/MWS Banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 173 KiB |
@@ -0,0 +1,4 @@
|
||||
title: MWS Banner.png
|
||||
type: image/png
|
||||
tags: picture
|
||||
alt-text: Banner for the new Multi Wiki Server plugin for TiddlyWiki
|
||||
@@ -0,0 +1,16 @@
|
||||
list-after: $:/core/ui/EditTemplate/title
|
||||
tags: $:/tags/EditTemplate
|
||||
title: $:/ContributionBanner
|
||||
|
||||
\define base-github()
|
||||
https://github.com/TiddlyWiki/TiddlyWiki5/edit/multi-wiki-support/editions/multiwikidocs/tiddlers/
|
||||
\end
|
||||
|
||||
<$set name="draft-of" value={{{ [<currentTiddler>get[draft.of]] }}}>
|
||||
<$list filter="[[$:/config/OriginalTiddlerPaths]getindex<draft-of>]" variable="target" >
|
||||
<div class="tc-improvement-banner">
|
||||
{{$:/core/images/star-filled}} Can you help us improve this documentation? [[Find out how|Improving TiddlyWiki Documentation]] to
|
||||
<a href={{{ [<target>addprefix<base-github>] }}} class="tc-tiddlylink-external" target="_blank" rel="noopener noreferrer">edit it directly on ~GitHub</a>
|
||||
</div>
|
||||
</$list>
|
||||
</$set>
|
||||
3
editions/multiwikidocs/tiddlers/system/SiteDomain.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/SiteDomain.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/SiteDomain
|
||||
|
||||
mws.tiddlywiki.com
|
||||
@@ -0,0 +1,3 @@
|
||||
title: $:/SitePreviewUrl
|
||||
|
||||
https://tiddlywiki.com/images/Introduction%2520Video%2520Thumbnail.jpg
|
||||
3
editions/multiwikidocs/tiddlers/system/SiteSubtitle.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/SiteSubtitle.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/SiteSubtitle
|
||||
|
||||
~TiddlyWiki for the People
|
||||
4
editions/multiwikidocs/tiddlers/system/SiteTitle.tid
Normal file
4
editions/multiwikidocs/tiddlers/system/SiteTitle.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/SiteTitle
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
~TiddlyWiki ~MultiWikiServer
|
||||
3
editions/multiwikidocs/tiddlers/system/SiteUrl.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/SiteUrl.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/SiteUrl
|
||||
|
||||
https://mws.tiddlywiki.com/
|
||||
129
editions/multiwikidocs/tiddlers/system/SplashScreen.tid
Normal file
129
editions/multiwikidocs/tiddlers/system/SplashScreen.tid
Normal file
@@ -0,0 +1,129 @@
|
||||
tags: $:/tags/RawMarkupWikified/TopBody
|
||||
title: $:/SplashScreen
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\import [subfilter{$:/core/config/GlobalImportFilter}]
|
||||
|
||||
\procedure show-icon(title)
|
||||
<$wikify name="icon" text={{{ [<title>addprefix[{{]addsuffix[}}]] }}} output="html">
|
||||
<$text text=<<icon>>/>
|
||||
</$wikify>
|
||||
\end
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrocallinline
|
||||
<div class="tc-remove-when-wiki-loaded">
|
||||
<style scoped>
|
||||
|
||||
.tc-splash-text {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 16px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
margin: 20px auto 0;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
color: <<colour foreground>>;
|
||||
fill: <<colour foreground>>;
|
||||
}
|
||||
|
||||
.tc-splash-text img {
|
||||
width: 150px;
|
||||
<<box-shadow "2px 2px 10px rgba(0, 0, 0, 0.5)">>
|
||||
}
|
||||
|
||||
html body.tc-body {
|
||||
background: <<colour page-background>>;
|
||||
}
|
||||
|
||||
/*
|
||||
Spinner from https://github.com/tobiasahlin/SpinKit/ by Tobias Ahlin
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Tobias Ahlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
.tc-splash-spinner {
|
||||
margin: 20px auto 0;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tc-splash-spinner > div {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
background-color: #f88;
|
||||
}
|
||||
|
||||
.tc-splash-spinner .tc-splash-bounce-1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
background-color: #8f8;
|
||||
}
|
||||
|
||||
.tc-splash-spinner .tc-splash-bounce-2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
background-color: #88f;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="tc-splash-spinner">
|
||||
<div class="tc-splash-bounce-1"></div>
|
||||
<div class="tc-splash-bounce-2"></div>
|
||||
<div class="tc-splash-bounce-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="tc-splash-text">
|
||||
<strong>{{$:/SiteTitle}}</strong>
|
||||
<br/>
|
||||
is loading
|
||||
</div>
|
||||
|
||||
<!-- Demonstrating how to embed a bitmap graphic -->
|
||||
<div class="tc-splash-text">
|
||||
<img src="data:image/jpeg;base64,{{MWS Banner.png||$:/core/templates/plain-text-tiddler}}" width="100"/>
|
||||
</div>
|
||||
|
||||
<!-- Demonstrating how to embed a wikitext SVG graphic -->
|
||||
<div class="tc-splash-text">
|
||||
<<show-icon "$:/core/icon">>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
3
editions/multiwikidocs/tiddlers/system/StaticBanner.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/StaticBanner.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/StaticBanner
|
||||
|
||||
<div class="tc-static-alert"><div class="tc-static-alert-inner">This page is part of a static HTML representation of the ~TiddlyWiki at https://tiddlywiki.com/</div></div>
|
||||
49
editions/multiwikidocs/tiddlers/system/Styles.tid
Normal file
49
editions/multiwikidocs/tiddlers/system/Styles.tid
Normal file
@@ -0,0 +1,49 @@
|
||||
tags: $:/tags/Stylesheet
|
||||
title: $:/_styles
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
|
||||
|
||||
.tc-improvement-banner {
|
||||
font-size: 0.7em;
|
||||
background: #fcc;
|
||||
padding-left: 5px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 12px;
|
||||
<<box-shadow "2px 2px 2px rgba(0,0,0,0.4)">>
|
||||
}
|
||||
|
||||
@media (max-width: {{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}}) {
|
||||
|
||||
.tc-improvement-banner {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: {{$:/themes/tiddlywiki/vanilla/metrics/sidebarbreakpoint}}) {
|
||||
|
||||
.tc-improvement-banner {
|
||||
margin-right: -53px;
|
||||
margin-left: -53px;
|
||||
}
|
||||
|
||||
.tc-improvement-banner:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
content: " ";
|
||||
margin-left: -5px;
|
||||
margin-top: -10px;
|
||||
border-top: 5px solid transparent;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid #C07E7E;
|
||||
border-bottom: 5px solid #C07E7E;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.tc-improvement-banner svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
tags: $:/tags/SideBar
|
||||
title: TableOfContents
|
||||
list-before:
|
||||
|
||||
<div class="tc-table-of-contents">
|
||||
|
||||
<<toc-selective-expandable 'TableOfContents'>>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
title: $:/config/DefaultSidebarTab
|
||||
|
||||
TableOfContents
|
||||
BIN
editions/multiwikidocs/tiddlers/system/favicon.png
Normal file
BIN
editions/multiwikidocs/tiddlers/system/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
2
editions/multiwikidocs/tiddlers/system/favicon.png.meta
Normal file
2
editions/multiwikidocs/tiddlers/system/favicon.png.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
||||
11
editions/multiwikidocs/tiddlers/system/macros.tid
Normal file
11
editions/multiwikidocs/tiddlers/system/macros.tid
Normal file
@@ -0,0 +1,11 @@
|
||||
code-body: yes
|
||||
tags: $:/tags/Macro
|
||||
title: $:/editions/multiwikidocs/doc-macros
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
\procedure .copy-code-to-clipboard(text)
|
||||
<div>
|
||||
<$transclude $variable="copy-to-clipboard-above-right" src=<<text>>/>
|
||||
<$codeblock code=<<text>>/>
|
||||
</div>
|
||||
\end .copy-code-to-clipboard
|
||||
149
editions/multiwikidocs/tiddlers/system/mws-palette.tid
Normal file
149
editions/multiwikidocs/tiddlers/system/mws-palette.tid
Normal file
@@ -0,0 +1,149 @@
|
||||
title: $:/palettes/MWS
|
||||
name: MWS Palette
|
||||
description: Palette for mws.tiddlywiki.com
|
||||
tags: $:/tags/Palette
|
||||
type: application/x-tiddler-dictionary
|
||||
|
||||
alert-background: #ffe476
|
||||
alert-border: #b99e2f
|
||||
alert-highlight: #881122
|
||||
alert-muted-foreground: #b99e2f
|
||||
background: #ffffff
|
||||
blockquote-bar: <<colour muted-foreground>>
|
||||
button-background:
|
||||
button-foreground:
|
||||
button-border:
|
||||
code-background: #f7f7f9
|
||||
code-border: #e1e1e8
|
||||
code-foreground: #dd1144
|
||||
diff-delete-background: #ffc9c9
|
||||
diff-delete-foreground: <<colour foreground>>
|
||||
diff-equal-background:
|
||||
diff-equal-foreground: <<colour foreground>>
|
||||
diff-insert-background: #aaefad
|
||||
diff-insert-foreground: <<colour foreground>>
|
||||
diff-invisible-background:
|
||||
diff-invisible-foreground: <<colour muted-foreground>>
|
||||
dirty-indicator: #ff0000
|
||||
download-background: #34c734
|
||||
download-foreground: <<colour background>>
|
||||
dragger-background: <<colour foreground>>
|
||||
dragger-foreground: <<colour background>>
|
||||
dropdown-background: <<colour background>>
|
||||
dropdown-border: <<colour muted-foreground>>
|
||||
dropdown-tab-background-selected: #ffffff
|
||||
dropdown-tab-background: #ececec
|
||||
dropzone-background: rgba(0,200,0,0.7)
|
||||
external-link-background-hover: inherit
|
||||
external-link-background-visited: inherit
|
||||
external-link-background: inherit
|
||||
external-link-foreground-hover: inherit
|
||||
external-link-foreground-visited: #0000aa
|
||||
external-link-foreground: #0000ee
|
||||
footnote-target-background: #ecf2ff
|
||||
foreground: #333333
|
||||
highlight-background: #ffff00
|
||||
highlight-foreground: #000000
|
||||
message-background: #ecf2ff
|
||||
message-border: #cfd6e6
|
||||
message-foreground: #547599
|
||||
modal-backdrop: <<colour foreground>>
|
||||
modal-background: <<colour background>>
|
||||
modal-border: #999999
|
||||
modal-footer-background: #f5f5f5
|
||||
modal-footer-border: #dddddd
|
||||
modal-header-border: #eeeeee
|
||||
muted-foreground: #bbbbbb
|
||||
network-activity-foreground: #448844
|
||||
notification-background: #ffffdd
|
||||
notification-border: #999999
|
||||
page-background: #eddee7
|
||||
pre-background: #f5f5f5
|
||||
pre-border: #cccccc
|
||||
primary: #5778d8
|
||||
selection-background:
|
||||
selection-foreground:
|
||||
select-tag-background:
|
||||
select-tag-foreground:
|
||||
sidebar-button-foreground: <<colour foreground>>
|
||||
sidebar-controls-foreground-hover: #000000
|
||||
sidebar-controls-foreground: #aaaaaa
|
||||
sidebar-foreground-shadow: rgba(255,255,255, 0.8)
|
||||
sidebar-foreground: #acacac
|
||||
sidebar-muted-foreground-hover: #444444
|
||||
sidebar-muted-foreground: #c0c0c0
|
||||
sidebar-tab-background-selected: #eddee7
|
||||
sidebar-tab-background: #c7b7bf
|
||||
sidebar-tab-border-selected: <<colour tab-border-selected>>
|
||||
sidebar-tab-border: <<colour tab-border>>
|
||||
sidebar-tab-divider: #e4e4e4
|
||||
sidebar-tab-foreground-selected:
|
||||
sidebar-tab-foreground: <<colour tab-foreground>>
|
||||
sidebar-tiddler-link-foreground-hover: #444444
|
||||
sidebar-tiddler-link-foreground: #999999
|
||||
site-title-foreground: <<colour tiddler-title-foreground>>
|
||||
stability-stable: #008000
|
||||
stability-experimental: #c07c00
|
||||
stability-deprecated: #ff0000
|
||||
stability-legacy: #0000ff
|
||||
static-alert-foreground: #aaaaaa
|
||||
tab-background-selected: #ffffff
|
||||
tab-background: #d8d8d8
|
||||
tab-border-selected: #d8d8d8
|
||||
tab-border: #cccccc
|
||||
tab-divider: #d8d8d8
|
||||
tab-foreground-selected: <<colour tab-foreground>>
|
||||
tab-foreground: #666666
|
||||
table-border: #dddddd
|
||||
table-footer-background: #a8a8a8
|
||||
table-header-background: #f0f0f0
|
||||
tag-background: #eecc66
|
||||
tag-foreground: #ffffff
|
||||
testcase-accent-level-1: #c1eaff
|
||||
testcase-accent-level-2: #E3B740
|
||||
testcase-accent-level-3: #5FD564
|
||||
tiddler-background: <<colour background>>
|
||||
tiddler-border: <<colour background>>
|
||||
tiddler-controls-foreground-hover: #888888
|
||||
tiddler-controls-foreground-selected: #444444
|
||||
tiddler-controls-foreground: #cccccc
|
||||
tiddler-editor-background: #f8f8f8
|
||||
tiddler-editor-border-image: #ffffff
|
||||
tiddler-editor-border: #cccccc
|
||||
tiddler-editor-fields-even: #e0e8e0
|
||||
tiddler-editor-fields-odd: #f0f4f0
|
||||
tiddler-info-background: #f8f8f8
|
||||
tiddler-info-border: #dddddd
|
||||
tiddler-info-tab-background: #f8f8f8
|
||||
tiddler-link-background: <<colour background>>
|
||||
tiddler-link-foreground: <<colour primary>>
|
||||
tiddler-subtitle-foreground: #c0c0c0
|
||||
tiddler-title-foreground: #182955
|
||||
toolbar-new-button:
|
||||
toolbar-options-button:
|
||||
toolbar-save-button:
|
||||
toolbar-info-button:
|
||||
toolbar-edit-button:
|
||||
toolbar-close-button:
|
||||
toolbar-delete-button:
|
||||
toolbar-cancel-button:
|
||||
toolbar-done-button:
|
||||
untagged-background: #999999
|
||||
very-muted-foreground: #888888
|
||||
wikilist-background: #e5e5e5
|
||||
wikilist-item: #ffffff
|
||||
wikilist-info: #000000
|
||||
wikilist-title: #666666
|
||||
wikilist-title-svg: <<colour wikilist-title>>
|
||||
wikilist-url: #aaaaaa
|
||||
wikilist-button-open: #4fb82b
|
||||
wikilist-button-open-hover: green
|
||||
wikilist-button-reveal: #5778d8
|
||||
wikilist-button-reveal-hover: blue
|
||||
wikilist-button-remove: #d85778
|
||||
wikilist-button-remove-hover: red
|
||||
wikilist-toolbar-background: #d3d3d3
|
||||
wikilist-toolbar-foreground: #888888
|
||||
wikilist-droplink-dragover: rgba(255,192,192,0.5)
|
||||
wikilist-button-background: #acacac
|
||||
wikilist-button-foreground: #000000
|
||||
3
editions/multiwikidocs/tiddlers/system/palette.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/palette.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/palette
|
||||
|
||||
$:/palettes/MWS
|
||||
3
editions/multiwikidocs/tiddlers/system/sidebarlayout.tid
Normal file
3
editions/multiwikidocs/tiddlers/system/sidebarlayout.tid
Normal file
@@ -0,0 +1,3 @@
|
||||
title: $:/themes/tiddlywiki/vanilla/options/sidebarlayout
|
||||
|
||||
fluid-fixed
|
||||
18
editions/multiwikidocs/tiddlers/system/static.content.tid
Normal file
18
editions/multiwikidocs/tiddlers/system/static.content.tid
Normal file
@@ -0,0 +1,18 @@
|
||||
title: $:/core/templates/static.content
|
||||
|
||||
\define tv-wikilink-template() https://tiddlywiki.com/static/$uri_doubleencoded$.html
|
||||
|
||||
<!-- For Google, and people without JavaScript-->
|
||||
|
||||
<$reveal default="yes" text=<<savingEmpty>> type="nomatch">
|
||||
|
||||
It looks like this browser doesn't run JavaScript. You can use one of these static HTML versions to browse the same content:
|
||||
|
||||
* https://mws.tiddlywiki.com/static.html - browse individual tiddlers as separate pages
|
||||
* https://mws.tiddlywiki.com/alltiddlers.html#HelloThere - single file containing all tiddlers
|
||||
|
||||
---
|
||||
|
||||
{{HelloThere}}
|
||||
|
||||
</$reveal>
|
||||
26
editions/multiwikidocs/tiddlywiki.info
Normal file
26
editions/multiwikidocs/tiddlywiki.info
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"description": "Multiple wiki server documentation edition",
|
||||
"plugins": [
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
"tiddlywiki/snowwhite"
|
||||
],
|
||||
"build": {
|
||||
"index": [
|
||||
"--savetiddlers","[tag[external-image]]","images",
|
||||
"--setfield","[tag[external-image]]","_canonical_uri","$:/core/templates/canonical-uri-external-image","text/plain",
|
||||
"--setfield","[tag[external-image]]","text","","text/plain",
|
||||
"--render","$:/core/save/all","index.html","text/plain"],
|
||||
"favicon": [
|
||||
"--savetiddler","$:/favicon.ico","favicon.ico"],
|
||||
"static": [
|
||||
"--render","$:/core/templates/static.template.html","static.html","text/plain",
|
||||
"--render","$:/core/templates/alltiddlers.template.html","alltiddlers.html","text/plain",
|
||||
"--render","[!is[system]]","[encodeuricomponent[]addprefix[static/]addsuffix[.html]]","text/plain","$:/core/templates/static.tiddler.html",
|
||||
"--render","$:/core/templates/static.template.css","static/static.css","text/plain"]
|
||||
},
|
||||
"config": {
|
||||
"retain-original-tiddler-path": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/config/MultiWikiServer/Engine
|
||||
text: better
|
||||
38
editions/multiwikiserver/tiddlywiki.info
Normal file
38
editions/multiwikiserver/tiddlywiki.info
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"description": "Multiple wiki client-server edition",
|
||||
"plugins": [
|
||||
"tiddlywiki/tiddlyweb",
|
||||
"tiddlywiki/filesystem",
|
||||
"tiddlywiki/multiwikiclient",
|
||||
"tiddlywiki/multiwikiserver"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
"tiddlywiki/snowwhite"
|
||||
],
|
||||
"build": {
|
||||
"load-mws-demo-data": [
|
||||
"--mws-load-wiki-folder","./editions/tw5.com","docs", "TiddlyWiki Documentation from https://tiddlywiki.com","docs","TiddlyWiki Documentation from https://tiddlywiki.com",
|
||||
"--mws-load-wiki-folder","./editions/dev","dev","TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev","dev-docs", "TiddlyWiki Developer Documentation from https://tiddlywiki.com/dev",
|
||||
"--mws-load-wiki-folder","./editions/tour","tour","TiddlyWiki Interactive Tour from https://tiddlywiki.com","tour", "TiddlyWiki Interactive Tour from https://tiddlywiki.com",
|
||||
"--mws-create-bag","bag-alpha","A test bag",
|
||||
"--mws-create-bag","bag-beta","Another test bag",
|
||||
"--mws-create-bag","bag-gamma","A further test bag",
|
||||
"--mws-create-recipe","recipe-rho","bag-alpha bag-beta","First wiki",
|
||||
"--mws-create-recipe","recipe-sigma","bag-alpha bag-gamma","Second Wiki",
|
||||
"--mws-create-recipe","recipe-tau","bag-alpha","Third Wiki",
|
||||
"--mws-create-recipe","recipe-upsilon","bag-alpha bag-gamma bag-beta","Fourth Wiki",
|
||||
"--mws-save-tiddler-text","bag-alpha","$:/SiteTitle","bag-alpha",
|
||||
"--mws-save-tiddler-text","bag-alpha","😀😃😄😁😆🥹😅😂","bag-alpha",
|
||||
"--mws-save-tiddler-text","bag-beta","$:/SiteTitle","bag-beta",
|
||||
"--mws-save-tiddler-text","bag-gamma","$:/SiteTitle","bag-gamma",
|
||||
"--mws-add-permission", "READ", "Allows user to create tiddlers",
|
||||
"--mws-add-permission", "WRITE", "Gives the user the permission to edit and delete tiddlers",
|
||||
"--mws-add-role", "ADMIN", "System Administrator",
|
||||
"--mws-add-role", "USER", "Basic User",
|
||||
"--mws-assign-role-permission", "ADMIN", "READ",
|
||||
"--mws-assign-role-permission", "ADMIN", "WRITE",
|
||||
"--mws-assign-role-permission", "USER", "READ"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/LocalPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: http://127.0.0.1:8080/prerelease/library/v5.3.6/index.html
|
||||
url: http://127.0.0.1:8080/prerelease/library/v5.3.7/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}} (Prerelease Local)
|
||||
|
||||
A locally installed version of the official ~TiddlyWiki plugin library at tiddlywiki.com for testing and debugging. //Requires a local web server to share the library//
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.3.6/index.html
|
||||
url: https://tiddlywiki.com/prerelease/library/v5.3.7/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}} (Prerelease)
|
||||
|
||||
The prerelease version of the official ~TiddlyWiki plugin library at tiddlywiki.com. Plugins, themes and language packs are maintained by the core team.
|
||||
|
||||
@@ -12,9 +12,9 @@ test('get started link', async ({ page }) => {
|
||||
|
||||
// Load the generated test TW html
|
||||
await page.goto(`file:///${crossPlatformIndexPath}`);
|
||||
|
||||
const title = await page.title();
|
||||
// Sanity check
|
||||
await expect(page.locator('.tc-site-title'), "Expected correct page title to verify the test page was loaded").toHaveText('TiddlyWiki5');
|
||||
await expect(title, "Expected correct page title to verify the test page was loaded").toContain('TiddlyWiki5');
|
||||
|
||||
// Wait for jasmine results bar to appear
|
||||
await expect(page.locator('.jasmine-overall-result'), "Expected jasmine test results bar to be present").toBeVisible({timeout});
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"description": "TiddlyWiki core tests",
|
||||
"plugins": [
|
||||
"tiddlywiki/jasmine",
|
||||
"tiddlywiki/multiwikiserver",
|
||||
"tiddlywiki/geospatial"
|
||||
],
|
||||
"themes": [
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
@@ -0,0 +1,3 @@
|
||||
title: $:/_tw_shared/favicons/mws.tiddlywiki.com
|
||||
type: image/png
|
||||
tags: TiddlyWikiSitesMenu
|
||||
@@ -0,0 +1,6 @@
|
||||
title: $:/_tw_shared/sites/mws.tiddlywiki.com
|
||||
tags: $:/tags/TiddlyWikiSites TiddlyWikiSitesMenu
|
||||
caption: mws.tiddlywiki.com
|
||||
description: ~MultiWikiServer Home
|
||||
url: https://mws.tiddlywiki.com/
|
||||
icon: $:/_tw_shared/favicons/mws.tiddlywiki.com
|
||||
@@ -1,3 +1,3 @@
|
||||
title: $:/tags/TiddlyWikiSites
|
||||
list: $:/_tw_shared/sites/tiddlywiki.com $:/_tw_shared/sites/tiddlywiki.org $:/_tw_shared/sites/talk.tiddlywiki.org $:/_tw_shared/sites/links.tiddlywiki.org $:/_tw_shared/sites/tiddlywiki.com.upgrade $:/_tw_shared/sites/tiddlywiki.com.dev $:/_tw_shared/sites/tiddlywiki.com.prerelease $:/_tw_shared/sites/classic.tiddlywiki.com $:/_tw_shared/sites/marketplace
|
||||
list: $:/_tw_shared/sites/tiddlywiki.com $:/_tw_shared/sites/tiddlywiki.org $:/_tw_shared/sites/talk.tiddlywiki.org $:/_tw_shared/sites/links.tiddlywiki.org $:/_tw_shared/sites/tiddlywiki.com.upgrade $:/_tw_shared/sites/tiddlywiki.com.dev $:/_tw_shared/sites/tiddlywiki.com.prerelease $:/_tw_shared/sites/mws.tiddlywiki.com $:/_tw_shared/sites/classic.tiddlywiki.com $:/_tw_shared/sites/marketplace
|
||||
tags: TiddlyWikiSitesMenu
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
created: 20231005205623086
|
||||
modified: 20240723172222378
|
||||
modified: 20241115193649399
|
||||
tags: About
|
||||
title: TiddlyWiki Archive
|
||||
|
||||
@@ -8,7 +8,7 @@ title: TiddlyWiki Archive
|
||||
5.1.10 5.1.11 5.1.12 5.1.13 5.1.14 5.1.15 5.1.16 5.1.17 5.1.18 5.1.19
|
||||
5.1.20 5.1.21 5.1.22 5.1.23
|
||||
5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7
|
||||
5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5
|
||||
5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6
|
||||
\end
|
||||
|
||||
Older versions of TiddlyWiki are available in the [[archive|https://github.com/TiddlyWiki/tiddlywiki.com-gh-pages/tree/master/archive]]:
|
||||
|
||||
@@ -2,7 +2,7 @@ title: HelloThumbnail - MultiWikiServer
|
||||
tags: HelloThumbnail
|
||||
color: purple
|
||||
background-color: #fff
|
||||
caption: Coming Soon
|
||||
caption: ~MultiWikiServer
|
||||
link: MultiWikiServer
|
||||
image: MWS Banner.png
|
||||
ribbon-text: SOON
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 104 KiB |
@@ -6,7 +6,23 @@ type: text/vnd.tiddlywiki
|
||||
\define tv-wikilink-template() https://tiddlywiki.com/static/$uri_doubleencoded$.html
|
||||
\import [subfilter{$:/core/config/GlobalImportFilter}]
|
||||
|
||||
! Welcome
|
||||
---
|
||||
|
||||
! ~TiddlyWiki ~MultiWikiServer
|
||||
|
||||
UNDER DEVELOPMENT
|
||||
|
||||
This is a branch of TiddlyWiki that adds the ~MultiWikiServer plugin.
|
||||
|
||||
!! Readme
|
||||
|
||||
{{$:/plugins/tiddlywiki/multiwikiserver/readme}}
|
||||
|
||||
!! Docs
|
||||
|
||||
{{$:/plugins/tiddlywiki/multiwikiserver/docs}}
|
||||
|
||||
---
|
||||
|
||||
Welcome to TiddlyWiki, a non-linear personal web notebook that anyone can use and keep forever, independently of any corporation.
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
caption: 5.3.6
|
||||
created: 20241115170824144
|
||||
modified: 20241115170824144
|
||||
description: Improved Geospatial Plugin, Markdown Plugin, TestCaseWidget, Usability and Bug fixes
|
||||
modified: 20241115194033978
|
||||
released: 20241115170824144
|
||||
tags: ReleaseNotes
|
||||
title: Release 5.3.6
|
||||
type: text/vnd.tiddlywiki
|
||||
description: Under development
|
||||
|
||||
//[[See GitHub for detailed change history of this release|https://github.com/TiddlyWiki/TiddlyWiki5/compare/v5.3.5...v5.3.6]]//
|
||||
|
||||
|
||||
@@ -3,9 +3,8 @@ tags: Definitions
|
||||
modified: 20241105133737778
|
||||
created: 20241105133737778
|
||||
|
||||
! Introduction
|
||||
|
||||
~MultiWikiServer is a new development that drastically improves ~TiddlyWiki's capabilities when running as server under Node.js. It brings ~TiddlyWiki up to par with common web-based tools like ~WordPress or ~MediaWiki by supporting multiple wikis and multiple users at the same time.
|
||||
<span class="tc-float-right tc-bordered-image">[img width=200 [MWS Banner.png]]</span>
|
||||
~MultiWikiServer is a new development that drastically improves ~TiddlyWiki's capabilities when running as a server under Node.js. It brings ~TiddlyWiki up to par with common web-based tools like ~WordPress or ~MediaWiki by supporting multiple wikis and multiple users at the same time.
|
||||
|
||||
Planned features include:
|
||||
|
||||
@@ -15,12 +14,13 @@ Planned features include:
|
||||
* Instantaneous synchronisation of changes between the server and all connected clients
|
||||
* Workflow processing on the server, for example to automatically compress images, or to archive webpages
|
||||
|
||||
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/TiddlyWiki5/pull/7915]] but it is already functional and usable.
|
||||
MWS does require basic knowledge of the command line and Node.js but is designed to be as simple as possible to setup and use. Once downloaded, just two commands are needed to complete the installation and start the server:
|
||||
|
||||
! Installing MWS
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
{{MWS: Installation}}
|
||||
MWS is currently [[under development at GitHub|https://github.com/TiddlyWiki/TiddlyWiki5/pull/7915]] but it is already functional and usable. Visit the MWS website for more information:
|
||||
|
||||
! Using MWS
|
||||
|
||||
{{MWS: Usage}}
|
||||
! https://mws.tiddlywiki.com/
|
||||
@@ -130,6 +130,25 @@ type: text/vnd.tiddlywiki
|
||||
}
|
||||
}
|
||||
|
||||
.tc-grid-columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(25em, 1fr));
|
||||
gap: 1em;
|
||||
width: 100%; /* Ensures container stretches fully */
|
||||
}
|
||||
|
||||
.tc-grid-columns.tc-grid-columns-2 > div {
|
||||
border-radius: 1em;
|
||||
padding: 1em;
|
||||
background-color: <<colour alert-background>>;
|
||||
}
|
||||
|
||||
.tc-grid-columns.tc-grid-columns-2 > div:nth-child(odd) {
|
||||
color: <<colour diff-delete-foreground>>;
|
||||
background-color: <<colour diff-delete-background>>;
|
||||
}
|
||||
|
||||
|
||||
.tc-saving-sidebar-category { margin-bottom:10px; }
|
||||
.tc-saving-sidebar-category-title { margin-bottom:5px; font-weight:bold; }
|
||||
.tc-saving-sidebar-category-item { margin-left:10px; white-space:nowrap; }
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
title: TiddlyWiki Node.js Privacy and Security
|
||||
tags: [[TiddlyWiki Privacy and Security]]
|
||||
|
||||
!!! Node.js Configuration
|
||||
|
||||
Using ~TiddlyWiki in the Node.js configuration requires more technical knowledge than the single file configuration. There are several important areas with respect to security and privacy.
|
||||
|
||||
* Most obviously, there is the matter of how user data is stored on disc as individual `.tid` files. Just as with the single file configuration, these are just ordinary files, and so can be used with third party tools that provide encryption.
|
||||
* Consideration must also be given to how data is transmitted across the network. By default, the Node.js configuration does not use SSL and so network traffic can be observed by others.
|
||||
** The impact of this is mitigated by the fact that, by default, only users on the same machine can connect to the server.
|
||||
** ~TiddlyWiki itself does offer the option of setting up an SSL connection. However, it is generally advised to use an external proxy server to provide SSL services. nginx is popular for this purpose.
|
||||
@@ -1,48 +1,55 @@
|
||||
title: TiddlyWiki Privacy and Security
|
||||
created: 20241106165307259
|
||||
modified: 20241106165307259
|
||||
modified: 20241117170845666
|
||||
title: TiddlyWiki Privacy and Security
|
||||
|
||||
<span class="tc-float-right">[img width=200 [TiddlyWiki Privacy Badge.png]]</span>
|
||||
TiddlyWiki is unique in that ordinary people without special training can use it securely and privately. It is easy to apply the advice from the EFF to ~TiddlyWiki. The key is that ~TiddlyWiki is just a file, and so everything that users may have already learned about how to keep documents and images private can be applied to ~TiddlyWiki.
|
||||
<span class="tc-float-right tc-bordered-image">[img width=200 [TiddlyWiki Privacy Badge.png]]</span>
|
||||
''TiddlyWiki is unique in that ordinary people can use it securely and privately without any special training.'' The key is that ~TiddlyWiki is just a text file, or a folder of files, so everything that you may already know about how to keep your documents and images private can be applied to ~TiddlyWiki. Also, because your ~TiddlyWiki data is stored in simple text files, you can be confident that it will still be securely accessible in the decades to come.
|
||||
|
||||
Because data is stored in simple text files, people choosing to use ~TiddlyWiki today can be confident that their data will still be accessible in the decades to come.
|
||||
!! ~TiddlyWiki Configurations
|
||||
|
||||
! Verifiable Trust
|
||||
~TiddlyWiki can be used in two main configurations:
|
||||
|
||||
An important aspect of ~TiddlyWiki's claims in the area of security and privacy is that these claims can be readily verified by anyone with basic technical skills. For example, the network monitoring tools built into browsers allow users to verify that ~TiddlyWiki doesn't send any data to other servers. Similarly anyone can open a ~TiddlyWiki HTML file in an editor and verify that their data is readily accessible.
|
||||
* As a single HTML file that contains all the data and code. This is the easiest setup, and the most widely supported.
|
||||
** Popular services like [[Tiddlyhost]] are based on the single file configuration
|
||||
** See [[Saving]] for a listing of all the different ways to save a single file ~TiddlyWiki
|
||||
* As a Node.js application that runs a web server. This configuration is more powerful, but requires more technical knowledge to set up and maintain. See:
|
||||
** [[Installing TiddlyWiki on Node.js]]
|
||||
** [[Using TiddlyWiki on Node.js]]
|
||||
|
||||
! Single File Configuration
|
||||
The security and privacy implications of the two configurations are different:
|
||||
|
||||
As a practical matter, using ~TiddlyWiki securely and privately in the single file configuration depends upon keeping that single file securely and privately.
|
||||
<div class="tc-grid-columns tc-grid-columns-2">
|
||||
|
||||
Users can employ the same tools that they use to keep any document and photograph secure. So, for many users, the simplest solution will be to use an existing file storage service such as Google Drive, Apple's iCloud, or Dropbox. Many users will already be relying on the privacy and security of these services.
|
||||
<div>
|
||||
|
||||
There are also open source alternatives such as [[Syncthing|https://syncthing.net/]] that allow users to synchronise files between their devices without using a third party service.
|
||||
{{TiddlyWiki Single File Privacy and Security}}
|
||||
|
||||
Users may wish to use additional layers of security. ~TiddlyWiki in the single file configuration itself offers built-in encryption. It uses an industry standard encryption library to offer AES 128 bit encryption in CCM mode. All the data within the file is encrypted, and cannot be accessed without entering the correct password. The password is never stored in the file, and so if it is lost, the data is lost. Instructions can be found in [[Encryption]].
|
||||
</div>
|
||||
|
||||
It is important to understand that ~TiddlyWiki's built in encryption is our best endeavour to offer privacy and usability. However, the encryption feature has not been subject to the kind of rigorous third party testing that characterises secure services like Signal or Syncthing.
|
||||
<div>
|
||||
|
||||
So, cautious users may wish to use ~TiddlyWiki's built in encryption as an extra layer of security, but should take care not to rely on it as one would rely on industry standard encryption solutions that have been rigorously tested in a variety of situations.
|
||||
{{TiddlyWiki Node.js Privacy and Security}}
|
||||
|
||||
! Node.js Configuration
|
||||
</div>
|
||||
|
||||
Using ~TiddlyWiki in the Node.js configuration requires more technical knowledge than the single file edition. There are several important areas with respect to security and privacy.
|
||||
</div>
|
||||
|
||||
Firstly, and most obviously, there is the matter of how user data is stored on disc as individual `.tid` files. Just as with the single file configuration, these are just ordinary files, and so can be used with third party tools that provide encryption.
|
||||
!! Verifiable Trust
|
||||
|
||||
Secondly, consideration must be given to how data is transmitted across the network. By default, the Node.js configuration does not use SSL and so traffic can be observed by others (the impact is mitigated by the fact that by default only users on the same machine can connect to the server). While ~TiddlyWiki itself does offer the option of setting up an SSL connection it is generally advised to use an external proxy server to provide SSL services. nginx is popular for this purpose.
|
||||
An important aspect of ~TiddlyWiki's security and privacy claims is that they can be readily confirmed by anyone with basic technical skills. For example, the network monitoring tools built into most browsers allow you to verify that ~TiddlyWiki doesn't send any data to other servers. Similarly, you can open a ~TiddlyWiki HTML file in an editor and verify that your data is readily accessible.
|
||||
|
||||
! Community Tools
|
||||
!! Community Tools
|
||||
|
||||
There are also third party tools from the community that extend ~TiddlyWiki's built in encryption:
|
||||
|
||||
* [["Encrypt single tiddler plugin" by Danielo Rodriguez]] allows individual tiddlers to be encrypted
|
||||
* [[TW5-CSEncryption|https://wiki.fspark.me/TW5-CSEncryption/]] offers client-side encryption for ~TiddlyWiki on Node.js
|
||||
|
||||
! Further Information
|
||||
!! Further Information
|
||||
|
||||
If security and privacy are important to you then you need to take the best available advice, and the best place for that is specialist organisations that focus on this area. The Electronic Frontier Foundation in the US is well respected, and their advice would be a good place to start. It emphasises basics such as dealing with passwords and two factor authentication, but also explains more advanced topics such as making a security plan, and how to set up a device securely.
|
||||
If security and privacy are important to you then you need to take the best available advice, and the best place for that is specialist organisations that focus on this area.
|
||||
|
||||
https://ssd.eff.org/module-categories/basics
|
||||
The [[Electronic Frontier Foundation (EFF)|https://eff.org]] in the US is well respected, and their advice would be a good place to start. It emphasises basics such as dealing with passwords and two factor authentication, but also explains more advanced topics such as making a security plan, and how to set up a device securely.
|
||||
|
||||
* https://ssd.eff.org/module-categories/basics
|
||||
* //Please suggest other useful privacy and security resources//
|
||||
@@ -0,0 +1,10 @@
|
||||
title: TiddlyWiki Single File Privacy and Security
|
||||
tags: [[TiddlyWiki Privacy and Security]]
|
||||
|
||||
!!! Single File Configuration
|
||||
|
||||
As a practical matter, using ~TiddlyWiki in the single file configuration depends upon keeping that file secure and private. You can employ the same tools that you use to keep your other documents and images secure. In most cases, the simplest solution will be to use an existing file storage service such as [[Google Drive|https://drive.google.com]], [[Apple's iCloud|https://www.icloud.com]], or [[Dropbox|https://www.dropbox.com]]. Many people already rely on the privacy and security of these services. There are also open source alternatives such as [[Syncthing|https://syncthing.net/]] that can allow you to synchronise files between your devices without using a third party service.
|
||||
|
||||
You may also wish to use additional layers of security. ~TiddlyWiki in the single file configuration offers built-in encryption using an industry standard encryption library to provide AES 128-bit encryption in CCM mode. All the data within the file is encrypted and cannot be accessed without entering the correct password. Your password is never stored in the file: if it is lost or forgotten, your data cannot be decrypted. Instructions can be found in [[Encryption]].
|
||||
|
||||
It is important to understand that ~TiddlyWiki's built in encryption is our best endeavour to offer privacy and usability. However, the encryption feature has not been subject to the kind of rigorous third party testing that characterises secure services like Signal or Syncthing. Cautious users may wish to use ~TiddlyWiki's built in encryption as an extra layer of security, but should take care not to rely on it as one would rely on industry standard encryption solutions that have been rigorously tested in a variety of situations.
|
||||
@@ -133,6 +133,7 @@ Excise/Caption/Replace/Transclusion: Transklusion
|
||||
Excise/Caption/Tag: Tagge den neuen Tiddler mit dem Titel des aktuellen Tiddlers
|
||||
Excise/Caption/TiddlerExists: Warnung: Tiddler existiert bereits!
|
||||
Excise/Hint: Verschiebe den ausgewählten Text in einen neuen Tiddler
|
||||
Excise/DefaultTitle: Neuen "Text Verschieben"
|
||||
Heading1/Caption: Überschrift 1
|
||||
Heading1/Hint: Überschrift 1 auf die Zeilen anwenden, die eine Auswahl enthalten
|
||||
Heading2/Caption: Überschrift 2
|
||||
|
||||
@@ -98,6 +98,10 @@ Plugins/Plugins/Hint: Erweiterungen
|
||||
Plugins/Reinstall/Caption: erneut installieren
|
||||
Plugins/Themes/Caption: Themes
|
||||
Plugins/Themes/Hint: Theme Erweiterungen
|
||||
Plugins/Stability/Deprecated: ABGEKÜNDIGT
|
||||
Plugins/Stability/Experimental: EXPERIMENTELL
|
||||
Plugins/Stability/Legacy: VERALTET
|
||||
Plugins/Stability/Stable: STABIL
|
||||
Plugins/Update/Caption: aktualisieren
|
||||
Plugins/Updates/Caption: Aktualisieren
|
||||
Plugins/Updates/Hint: Verfügbare Erweiterungen zu bereits installierten "Plugins"
|
||||
@@ -171,6 +175,8 @@ Settings/NavigationPermalinkviewMode/UpdateAddressBar/Description: Adressleiste
|
||||
Settings/PerformanceInstrumentation/Caption: Performance Messung
|
||||
Settings/PerformanceInstrumentation/Hint: Anzeige der Performance Statistik in der Browser Entwickler Konsole. ''Wichtig:'' Seite neu laden um die Einstellung zu aktivieren!
|
||||
Settings/PerformanceInstrumentation/Description: Aktiviere Performance Messung
|
||||
Settings/RecentLimit/Caption: Zuletzt Limit
|
||||
Settings/RecentLimit/Hint: Maximale Anzahl von angezeigten "Tiddlern" im "Zuletzt" Reiter
|
||||
Settings/ToolbarButtonStyle/Caption: Toolbar Button Stil
|
||||
Settings/ToolbarButtonStyle/Hint: Wählen Sie einen Stil:
|
||||
Settings/ToolbarButtonStyle/Styles/Borderless: Ohne Rand
|
||||
@@ -198,6 +204,12 @@ Settings/TitleLinks/Yes/Description: Tiddler Titel als Link anzeigen.
|
||||
Settings/MissingLinks/Caption: Wiki-Links
|
||||
Settings/MissingLinks/Hint: Aktiviere Links zu fehlenden Tiddlern. zB: FehlenderTiddler [[Einführung]]
|
||||
Settings/MissingLinks/Description: Aktiviere Links zu fehlenden Tiddlern.
|
||||
SocialCard/Caption: Social Media Karte
|
||||
SocialCard/Domain/Prompt: Domain Name für Link Anzeige. Zb: ''tiddlywiki.com''
|
||||
SocialCard/Hint: Diese Information wird verwendet, wenn eine "Voransicht" eines Links angezeigt werden soll
|
||||
SocialCard/PreviewUrl/Prompt: Vollständige URL für die Media-Vorschau für dieses ~TiddlyWiki
|
||||
SocialCard/PreviewUrl/Preview: Vorschau Bild:
|
||||
SocialCard/Url/Prompt: Vollständige URL für dieses ~TiddlyWiki
|
||||
StoryTiddler/Caption: Story Tiddler
|
||||
StoryTiddler/Hint: Diese Filter-Kaskade wird verwendet, um die Vorlage für den Tiddler im "Story River" auszuwählen.
|
||||
StoryView/Caption: Anzeige
|
||||
|
||||
@@ -26,6 +26,8 @@ Tags/ClearInput/Caption: lösche Eingabefeld
|
||||
Tags/ClearInput/Hint: Lösche Tag Eingabefeld
|
||||
Tags/Dropdown/Caption: Tag Liste
|
||||
Tags/Dropdown/Hint: Tag Liste anzeigen
|
||||
Tags/EmptyMessage: Kein Tag gefunden
|
||||
Tags/EmptyMessage/System: Kein System Tag gefunden
|
||||
Title/BadCharacterWarning: Warnung: Folgende Zeichen im Titel können zu Problemen führen: <<bad-chars>>
|
||||
Title/Exists/Prompt: Tiddler Name existiert bereits
|
||||
Title/Relink/Prompt: Ändere ''<$text text=<<fromTitle>>/>'' -> ''<$text text=<<toTitle>>/>'' in //tags// und //list// Feld aller anderen Tiddler
|
||||
|
||||
@@ -6,6 +6,8 @@ Filter/Hint: Suche mit [["filter expression"|https://tiddlywiki.com/static/Filte
|
||||
Filter/Matches: //<small><<resultCount>> Treffer</small>//
|
||||
Matches: //<small><<resultCount>> Treffer</small>//
|
||||
Matches/All: Alle Treffer:
|
||||
Matches/NoMatch: //Kein Treffer//
|
||||
Matches/NoResult: //Kein Suchergebnis//
|
||||
Matches/Title: Titel Treffer:
|
||||
Search: Suchen
|
||||
Search/TooShort: Suchtext ist zu kurz
|
||||
@@ -14,7 +16,7 @@ Shadows/Hint: Suche in Schatten-Tiddlern.
|
||||
Shadows/Matches: //<small><<resultCount>> Treffer</small>//
|
||||
Standard/Caption: Standard
|
||||
Standard/Hint: Suche in Standard-Tiddlern.
|
||||
Standard/Matches: //<small><<resultCount>> matches</small>//
|
||||
Standard/Matches: //<small><<resultCount>> Treffer</small>//
|
||||
System/Caption: System
|
||||
System/Hint: Suche in System-Tiddlern.
|
||||
System/Matches: //<small><<resultCount>> Treffer</small>//
|
||||
1474
package-lock.json
generated
Normal file
1474
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tiddlywiki",
|
||||
"preferGlobal": "true",
|
||||
"version": "5.3.6",
|
||||
"version": "5.3.7-prerelease",
|
||||
"author": "Jeremy Ruston <jeremy@jermolene.com>",
|
||||
"description": "a non-linear personal web notebook",
|
||||
"contributors": [
|
||||
@@ -24,18 +24,26 @@
|
||||
"wiki"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.47.2",
|
||||
"eslint": "^9.12.0",
|
||||
"@eslint/js": "^9.12.0"
|
||||
"@eslint/js": "^9.12.0",
|
||||
"playwright": "^1.47.2"
|
||||
},
|
||||
"bundleDependencies": [],
|
||||
"license": "BSD",
|
||||
"engines": {
|
||||
"node": ">=0.8.2"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "node ./tiddlywiki.js ./editions/tw5.com-server --listen",
|
||||
"test": "node ./tiddlywiki.js ./editions/test --verbose --version --build index",
|
||||
"start": "node ./tiddlywiki.js ./editions/multiwikiserver --mws-load-plugin-bags --build load-mws-demo-data --mws-listen",
|
||||
"build:test-edition": "node ./tiddlywiki.js ./editions/test --verbose --version --build index",
|
||||
"test:multiwikiserver-edition": "node ./tiddlywiki.js ./editions/multiwikiserver/ --build load-mws-demo-data --mws-listen --mws-test-server http://127.0.0.1:8080/ --quit",
|
||||
"mws-add-user": "node ./tiddlywiki.js ./editions/multiwikiserver --build load-mws-demo-data --mws-listen --build mws-add-user --quit",
|
||||
"test": "npm run build:test-edition && npm run test:multiwikiserver-edition",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "^11.5.0",
|
||||
"node-sqlite3-wasm": "^0.8.25"
|
||||
}
|
||||
}
|
||||
|
||||
9
plugins/tiddlywiki/multiwikiclient/GettingStarted.tid
Normal file
9
plugins/tiddlywiki/multiwikiclient/GettingStarted.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: GettingStarted
|
||||
tags: $:/tags/GettingStarted
|
||||
caption: Step 1<br>Syncing
|
||||
|
||||
! ~TiddlyWiki ~MultiWikiServer
|
||||
|
||||
Welcome to ~TiddlyWiki and the ~TiddlyWiki community.
|
||||
|
||||
Please note that ~MultiWikiServer is under active development, and may not be fully robust. Do not use it for anything critical.
|
||||
@@ -0,0 +1,3 @@
|
||||
title: $:/config/SaveWikiButton/Template
|
||||
|
||||
$:/plugins/tiddlywiki/multiwikiclient/save/offline
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/config/multiwikiclient/incoming-updates-filter
|
||||
text: [all[]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/library/sjcl.js]] -[[$:/core]] -[prefix[$:/StoryList]] -[prefix[$:/HistoryList]]
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/config/Server/ExternalFilters/[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/library/sjcl.js]] -[[$:/core]]
|
||||
text: yes
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/config/multiwikiclient/use-server-sent-events
|
||||
text: no
|
||||
@@ -0,0 +1,7 @@
|
||||
title: $:/config/OfficialPluginLibrary
|
||||
tags: $:/tags/PluginLibrary
|
||||
url: https://tiddlywiki.com/library/v5.1.23/index.html
|
||||
caption: {{$:/language/OfficialPluginLibrary}}
|
||||
enabled: no
|
||||
|
||||
The official plugin library is disabled when using the client-server configuration. Instead, plugins should be installed via the `tiddlywiki.info` file, as described [[here|https://tiddlywiki.com/#Installing%20a%20plugin%20from%20the%20plugin%20library]].
|
||||
4
plugins/tiddlywiki/multiwikiclient/icon-cloud.tid
Normal file
4
plugins/tiddlywiki/multiwikiclient/icon-cloud.tid
Normal file
@@ -0,0 +1,4 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/icon/cloud
|
||||
tags: $:/tags/Image
|
||||
|
||||
<svg class="tc-image-cloud tc-image-button" width="22pt" height="22pt" viewBox="0 0 128 128"><g><path d="M24 103C10.745 103 0 92.255 0 79c0-9.697 5.75-18.05 14.027-21.836A24.787 24.787 0 0114 56c0-13.255 10.745-24 24-24 1.373 0 2.718.115 4.028.337C48.628 24.2 58.707 19 70 19c19.882 0 36 16.118 36 36v.082c12.319 1.016 22 11.336 22 23.918 0 12.239-9.16 22.337-20.999 23.814L107 103H24z"/><path class="tc-image-cloud-idle" d="M57.929 84.698a6 6 0 01-8.485 0L35.302 70.556a6 6 0 118.485-8.485l9.9 9.9L81.97 43.686a6 6 0 018.485 8.486L57.929 84.698z"/><path class="tc-image-cloud-progress tc-animate-rotate-slow" d="M44.8 40a3.6 3.6 0 100 7.2h2.06A23.922 23.922 0 0040 64c0 13.122 10.531 23.785 23.603 23.997L64 88l.001-7.2c-9.171 0-16.626-7.348-16.798-16.477L47.2 64c0-5.165 2.331-9.786 5.999-12.868L53.2 55.6a3.6 3.6 0 107.2 0v-12a3.6 3.6 0 00-3.6-3.6h-12zM64 40v7.2c9.278 0 16.8 7.522 16.8 16.8 0 5.166-2.332 9.787-6 12.869V72.4a3.6 3.6 0 10-7.2 0v12a3.6 3.6 0 003.6 3.6h12a3.6 3.6 0 100-7.2l-2.062.001A23.922 23.922 0 0088 64c0-13.255-10.745-24-24-24z"/></g></svg>
|
||||
8
plugins/tiddlywiki/multiwikiclient/info-segment.tid
Normal file
8
plugins/tiddlywiki/multiwikiclient/info-segment.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/info-segment
|
||||
tags: $:/tags/TiddlerInfoSegment
|
||||
|
||||
<$reveal type="nomatch" state=<<folded-state>> text="hide" tag="div" retain="yes" animate="yes">
|
||||
<div class="tc-subtitle">
|
||||
Bag: <$view tiddler="$:/state/multiwikiclient/tiddlers/bag" index=<<currentTiddler>>>(none)</$view>
|
||||
</div>
|
||||
</$reveal>
|
||||
16
plugins/tiddlywiki/multiwikiclient/manage-acl.tid
Normal file
16
plugins/tiddlywiki/multiwikiclient/manage-acl.tid
Normal file
@@ -0,0 +1,16 @@
|
||||
title: $:/core/ui/Buttons/manage-acl
|
||||
tags: $:/tags/PageControls
|
||||
caption: {{$:/core/images/globe}} manage access control
|
||||
description: Manage access control configuration for this wiki
|
||||
list-after: $:/core/ui/Buttons/encryption
|
||||
|
||||
\whitespace trim
|
||||
<$button tooltip="Manage access control configuration for this wiki" aria-label="manage access control" class=<<tv-config-toolbar-class>>>
|
||||
<$action-managetiddler tiddler=<<currentTiddler>>/>
|
||||
{{$:/core/images/globe}}
|
||||
<%if [<tv-config-toolbar-text>match[yes]] %>
|
||||
<span class="tc-btn-text">
|
||||
<$text text={{$:/language/Buttons/ManageACL/Caption}}/>
|
||||
</span>
|
||||
<%endif%>
|
||||
</$button>
|
||||
65
plugins/tiddlywiki/multiwikiclient/managetiddleraction.js
Normal file
65
plugins/tiddlywiki/multiwikiclient/managetiddleraction.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/managetiddleraction.js
|
||||
type: application/javascript
|
||||
module-type: widget
|
||||
|
||||
A widget to manage tiddler actions.
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var Widget = require("$:/core/modules/widgets/widget.js").widget;
|
||||
|
||||
var ManageTiddlerAction = function(parseTreeNode,options) {
|
||||
this.initialise(parseTreeNode,options);
|
||||
};
|
||||
|
||||
/*
|
||||
Inherit from the base widget class
|
||||
*/
|
||||
ManageTiddlerAction.prototype = new Widget();
|
||||
|
||||
/*
|
||||
Render this widget into the DOM
|
||||
*/
|
||||
ManageTiddlerAction.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
};
|
||||
|
||||
/*
|
||||
Compute the internal state of the widget
|
||||
*/
|
||||
ManageTiddlerAction.prototype.execute = function() {
|
||||
this.tiddler = this.getAttribute("tiddler");
|
||||
};
|
||||
|
||||
/*
|
||||
Invoke the action associated with this widget
|
||||
*/
|
||||
ManageTiddlerAction.prototype.invokeAction = function(triggeringWidget,event) {
|
||||
var pathname = window.location.pathname;
|
||||
var paths = pathname.split("/");
|
||||
var recipeName = paths[paths.length - 1];
|
||||
var bagName = document.querySelector("h1.tc-site-title").innerHTML;
|
||||
window.location.href = "/admin/acl/"+recipeName+"/"+bagName;
|
||||
};
|
||||
|
||||
/*
|
||||
Refresh the widget by ensuring our attributes are up to date
|
||||
*/
|
||||
ManageTiddlerAction.prototype.refresh = function(changedTiddlers) {
|
||||
var changedAttributes = this.computeAttributes();
|
||||
if(changedAttributes.tiddler) {
|
||||
this.refreshSelf();
|
||||
return true;
|
||||
}
|
||||
return this.refreshChildren(changedTiddlers);
|
||||
};
|
||||
|
||||
exports["action-managetiddler"] = ManageTiddlerAction;
|
||||
|
||||
})();
|
||||
399
plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
Normal file
399
plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
Normal file
@@ -0,0 +1,399 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
|
||||
type: application/javascript
|
||||
module-type: syncadaptor
|
||||
|
||||
A sync adaptor module for synchronising with MultiWikiServer-compatible servers. It has three key areas of concern:
|
||||
|
||||
* Basic operations like put, get, and delete a tiddler on the server
|
||||
* Real time updates from the server (handled by SSE)
|
||||
* Managing login/logout (not yet implemeneted)
|
||||
* Bags and recipes, which are unknown to the syncer
|
||||
|
||||
A key aspect of the design is that the syncer never overlaps basic server operations; it waits for the
|
||||
previous operation to complete before sending a new one.
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var CONFIG_HOST_TIDDLER = "$:/config/multiwikiclient/host",
|
||||
DEFAULT_HOST_TIDDLER = "$protocol$//$host$/",
|
||||
MWC_STATE_TIDDLER_PREFIX = "$:/state/multiwikiclient/",
|
||||
BAG_STATE_TIDDLER = "$:/state/multiwikiclient/tiddlers/bag",
|
||||
REVISION_STATE_TIDDLER = "$:/state/multiwikiclient/tiddlers/revision",
|
||||
CONNECTION_STATE_TIDDLER = "$:/state/multiwikiclient/connection",
|
||||
INCOMING_UPDATES_FILTER_TIDDLER = "$:/config/multiwikiclient/incoming-updates-filter",
|
||||
ENABLE_SSE_TIDDLER = "$:/config/multiwikiclient/use-server-sent-events";
|
||||
|
||||
var SERVER_NOT_CONNECTED = "NOT CONNECTED",
|
||||
SERVER_CONNECTING_SSE = "CONNECTING SSE",
|
||||
SERVER_CONNECTED_SSE = "CONNECTED SSE",
|
||||
SERVER_POLLING = "SERVER POLLING";
|
||||
|
||||
function MultiWikiClientAdaptor(options) {
|
||||
this.wiki = options.wiki;
|
||||
this.host = this.getHost();
|
||||
this.recipe = this.wiki.getTiddlerText("$:/config/multiwikiclient/recipe");
|
||||
this.useServerSentEvents = this.wiki.getTiddlerText(ENABLE_SSE_TIDDLER) === "yes";
|
||||
this.last_known_tiddler_id = $tw.utils.parseNumber(this.wiki.getTiddlerText("$:/state/multiwikiclient/recipe/last_tiddler_id","0"));
|
||||
this.outstandingRequests = Object.create(null); // Hashmap by title of outstanding request object: {type: "PUT"|"GET"|"DELETE"}
|
||||
this.lastRecordedUpdate = Object.create(null); // Hashmap by title of last recorded update via SSE: {type: "update"|"detetion", tiddler_id:}
|
||||
this.logger = new $tw.utils.Logger("MultiWikiClientAdaptor");
|
||||
this.isLoggedIn = false;
|
||||
this.isReadOnly = false;
|
||||
this.logoutIsAvailable = true;
|
||||
// Compile the dirty tiddler filter
|
||||
this.incomingUpdatesFilterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(INCOMING_UPDATES_FILTER_TIDDLER));
|
||||
this.setUpdateConnectionStatus(SERVER_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
MultiWikiClientAdaptor.prototype.setUpdateConnectionStatus = function(status) {
|
||||
this.serverUpdateConnectionStatus = status;
|
||||
this.wiki.addTiddler({
|
||||
title: CONNECTION_STATE_TIDDLER,
|
||||
text: status
|
||||
});
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.name = "multiwikiclient";
|
||||
|
||||
MultiWikiClientAdaptor.prototype.supportsLazyLoading = true;
|
||||
|
||||
MultiWikiClientAdaptor.prototype.setLoggerSaveBuffer = function(loggerForSaving) {
|
||||
this.logger.setSaveBuffer(loggerForSaving);
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.isReady = function() {
|
||||
return true;
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.getHost = function() {
|
||||
var text = this.wiki.getTiddlerText(CONFIG_HOST_TIDDLER,DEFAULT_HOST_TIDDLER),
|
||||
substitutions = [
|
||||
{name: "protocol", value: document.location.protocol},
|
||||
{name: "host", value: document.location.host},
|
||||
{name: "pathname", value: document.location.pathname}
|
||||
];
|
||||
for(var t=0; t<substitutions.length; t++) {
|
||||
var s = substitutions[t];
|
||||
text = $tw.utils.replaceString(text,new RegExp("\\$" + s.name + "\\$","mg"),s.value);
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.getTiddlerInfo = function(tiddler) {
|
||||
var title = tiddler.fields.title,
|
||||
revision = this.wiki.extractTiddlerDataItem(REVISION_STATE_TIDDLER,title),
|
||||
bag = this.wiki.extractTiddlerDataItem(BAG_STATE_TIDDLER,title);
|
||||
if(revision && bag) {
|
||||
return {
|
||||
title: title,
|
||||
revision: revision,
|
||||
bag: bag
|
||||
};
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.getTiddlerBag = function(title) {
|
||||
return this.wiki.extractTiddlerDataItem(BAG_STATE_TIDDLER,title);
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.getTiddlerRevision = function(title) {
|
||||
return this.wiki.extractTiddlerDataItem(REVISION_STATE_TIDDLER,title);
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.setTiddlerInfo = function(title,revision,bag) {
|
||||
this.wiki.setText(BAG_STATE_TIDDLER,null,title,bag,{suppressTimestamp: true});
|
||||
this.wiki.setText(REVISION_STATE_TIDDLER,null,title,revision,{suppressTimestamp: true});
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.removeTiddlerInfo = function(title) {
|
||||
this.wiki.setText(BAG_STATE_TIDDLER,null,title,undefined,{suppressTimestamp: true});
|
||||
this.wiki.setText(REVISION_STATE_TIDDLER,null,title,undefined,{suppressTimestamp: true});
|
||||
};
|
||||
|
||||
/*
|
||||
Get the current status of the server connection
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.getStatus = function(callback) {
|
||||
// Invoke the callback if present
|
||||
if(callback) {
|
||||
callback(
|
||||
null, // Error
|
||||
true, // Is logged in
|
||||
this.username, // Username
|
||||
false, // Is read only
|
||||
true // Is anonymous
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Get details of changed tiddlers from the server
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.getUpdatedTiddlers = function(syncer,callback) {
|
||||
if(this.useServerSentEvents) {
|
||||
var self = this;
|
||||
// Do nothing if there's already a connection in progress.
|
||||
if(this.serverUpdateConnectionStatus !== SERVER_NOT_CONNECTED) {
|
||||
return callback(null,{
|
||||
modifications: [],
|
||||
deletions: []
|
||||
});
|
||||
}
|
||||
// Try to connect a server stream
|
||||
this.setUpdateConnectionStatus(SERVER_CONNECTING_SSE);
|
||||
this.connectServerStream({
|
||||
syncer: syncer,
|
||||
onerror: function(err) {
|
||||
self.logger.log("Error connecting SSE stream",err);
|
||||
// If the stream didn't work, try polling
|
||||
self.setUpdateConnectionStatus(SERVER_POLLING);
|
||||
self.pollServer({
|
||||
callback: function(err,changes) {
|
||||
self.setUpdateConnectionStatus(SERVER_NOT_CONNECTED);
|
||||
callback(null,changes);
|
||||
}
|
||||
});
|
||||
},
|
||||
onopen: function() {
|
||||
self.setUpdateConnectionStatus(SERVER_CONNECTED_SSE);
|
||||
// The syncer is expecting a callback but we don't have any data to send
|
||||
callback(null,{
|
||||
modifications: [],
|
||||
deletions: []
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.pollServer({
|
||||
callback: function(err,changes) {
|
||||
callback(null,changes);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Attempt to establish an SSE stream with the server and transfer tiddler changes. Options include:
|
||||
|
||||
syncer: reference to syncer object used for storing data
|
||||
onopen: invoked when the stream is successfully opened
|
||||
onerror: invoked if there is an error
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.connectServerStream = function(options) {
|
||||
var self = this;
|
||||
const eventSource = new EventSource("/recipes/" + this.recipe + "/events?last_known_tiddler_id=" + this.last_known_tiddler_id);
|
||||
eventSource.onerror = function(event) {
|
||||
if(options.onerror) {
|
||||
options.onerror(event);
|
||||
}
|
||||
}
|
||||
eventSource.onopen = function(event) {
|
||||
if(options.onopen) {
|
||||
options.onopen(event);
|
||||
}
|
||||
}
|
||||
eventSource.addEventListener("change", function(event) {
|
||||
const data = $tw.utils.parseJSONSafe(event.data);
|
||||
if(data) {
|
||||
console.log("SSE data",data)
|
||||
// Update last seen tiddler_id
|
||||
if(data.tiddler_id > self.last_known_tiddler_id) {
|
||||
self.last_known_tiddler_id = data.tiddler_id;
|
||||
}
|
||||
// Record the last update to this tiddler
|
||||
self.lastRecordedUpdate[data.title] = {
|
||||
type: data.is_deleted ? "deletion" : "update",
|
||||
tiddler_id: data.tiddler_id
|
||||
};
|
||||
console.log(`Oustanding requests is ${JSON.stringify(self.outstandingRequests[data.title])}`)
|
||||
// Process the update if the tiddler is not the subject of an outstanding request
|
||||
if(!self.outstandingRequests[data.title]) {
|
||||
if(data.is_deleted) {
|
||||
self.removeTiddlerInfo(data.title);
|
||||
delete options.syncer.tiddlerInfo[data.title];
|
||||
options.syncer.logger.log("Deleting tiddler missing from server:",data.title);
|
||||
options.syncer.wiki.deleteTiddler(data.title);
|
||||
options.syncer.processTaskQueue();
|
||||
} else {
|
||||
var result = self.incomingUpdatesFilterFn.call(self.wiki,self.wiki.makeTiddlerIterator([data.title]));
|
||||
if(result.length > 0) {
|
||||
self.setTiddlerInfo(data.title,data.tiddler_id.toString(),data.bag_name);
|
||||
options.syncer.storeTiddler(data.tiddler);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Poll the server for changes. Options include:
|
||||
|
||||
callback: invoked on completion as (err,changes)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.pollServer = function(options) {
|
||||
var self = this;
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + this.recipe + "/tiddlers.json",
|
||||
data: {
|
||||
last_known_tiddler_id: this.last_known_tiddler_id,
|
||||
include_deleted: "true"
|
||||
},
|
||||
callback: function(err,data) {
|
||||
// Check for errors
|
||||
if(err) {
|
||||
return options.callback(err);
|
||||
}
|
||||
var modifications = [],
|
||||
deletions = [];
|
||||
var tiddlerInfoArray = $tw.utils.parseJSONSafe(data);
|
||||
$tw.utils.each(tiddlerInfoArray,function(tiddlerInfo) {
|
||||
if(tiddlerInfo.tiddler_id > self.last_known_tiddler_id) {
|
||||
self.last_known_tiddler_id = tiddlerInfo.tiddler_id;
|
||||
}
|
||||
if(tiddlerInfo.is_deleted) {
|
||||
deletions.push(tiddlerInfo.title);
|
||||
} else {
|
||||
modifications.push(tiddlerInfo.title);
|
||||
}
|
||||
});
|
||||
// Invoke the callback with the results
|
||||
options.callback(null,{
|
||||
modifications: modifications,
|
||||
deletions: deletions
|
||||
});
|
||||
// If Browswer Storage tiddlers were cached on reloading the wiki, add them after sync from server completes in the above callback.
|
||||
if($tw.browserStorage && $tw.browserStorage.isEnabled()) {
|
||||
$tw.browserStorage.addCachedTiddlers();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Queue a load for a tiddler if there has been an update for it since the specified revision
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.checkLastRecordedUpdate = function(title,revision,syncer) {
|
||||
var lru = this.lastRecordedUpdate[title];
|
||||
if(lru) {
|
||||
var numRevision = $tw.utils.getInt(revision);
|
||||
console.log(`Checking for updates to ${title} since ${JSON.stringify(revision)} comparing to ${numRevision}`)
|
||||
if(lru.tiddler_id > numRevision) {
|
||||
options.syncer.enqueueLoadTiddler(title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.saveTiddler = function(tiddler,callback,options) {
|
||||
var self = this,
|
||||
title = tiddler.fields.title;
|
||||
if(this.isReadOnly || title.substr(0,MWC_STATE_TIDDLER_PREFIX.length) === MWC_STATE_TIDDLER_PREFIX) {
|
||||
return callback(null);
|
||||
}
|
||||
self.outstandingRequests[title] = {type: "PUT"};
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + encodeURIComponent(this.recipe) + "/tiddlers/" + encodeURIComponent(title),
|
||||
type: "PUT",
|
||||
headers: {
|
||||
"Content-type": "application/json"
|
||||
},
|
||||
data: JSON.stringify(tiddler.getFieldStrings()),
|
||||
callback: function(err,data,request) {
|
||||
delete self.outstandingRequests[title];
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
//If Browser-Storage plugin is present, remove tiddler from local storage after successful sync to the server
|
||||
if($tw.browserStorage && $tw.browserStorage.isEnabled()) {
|
||||
$tw.browserStorage.removeTiddlerFromLocalStorage(title)
|
||||
}
|
||||
// Save the details of the new revision of the tiddler
|
||||
var revision = request.getResponseHeader("X-Revision-Number"),
|
||||
bag_name = request.getResponseHeader("X-Bag-Name");
|
||||
console.log(`Saved ${title} with revision ${revision} and bag ${bag_name}`)
|
||||
// If there has been a more recent update from the server then enqueue a load of this tiddler
|
||||
self.checkLastRecordedUpdate(title,revision,options.syncer);
|
||||
// Invoke the callback
|
||||
self.setTiddlerInfo(title,revision,bag_name);
|
||||
callback(null,{bag: bag_name},revision);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Load a tiddler and invoke the callback with (err,tiddlerFields)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.loadTiddler = function(title,callback,options) {
|
||||
var self = this;
|
||||
self.outstandingRequests[title] = {type: "GET"};
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + encodeURIComponent(this.recipe) + "/tiddlers/" + encodeURIComponent(title),
|
||||
callback: function(err,data,request) {
|
||||
delete self.outstandingRequests[title];
|
||||
if(err === 404) {
|
||||
return callback(null,null);
|
||||
} else if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
var revision = request.getResponseHeader("X-Revision-Number"),
|
||||
bag_name = request.getResponseHeader("X-Bag-Name");
|
||||
// If there has been a more recent update from the server then enqueue a load of this tiddler
|
||||
self.checkLastRecordedUpdate(title,revision,options.syncer);
|
||||
// Invoke the callback
|
||||
self.setTiddlerInfo(title,revision,bag_name);
|
||||
callback(null,$tw.utils.parseJSONSafe(data));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Delete a tiddler and invoke the callback with (err)
|
||||
options include:
|
||||
tiddlerInfo: the syncer's tiddlerInfo for this tiddler
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.deleteTiddler = function(title,callback,options) {
|
||||
var self = this;
|
||||
if(this.isReadOnly) {
|
||||
return callback(null);
|
||||
}
|
||||
// If we don't have a bag it means that the tiddler hasn't been seen by the server, so we don't need to delete it
|
||||
var bag = this.getTiddlerBag(title);
|
||||
if(!bag) {
|
||||
return callback(null,options.tiddlerInfo.adaptorInfo);
|
||||
}
|
||||
self.outstandingRequests[title] = {type: "DELETE"};
|
||||
// Issue HTTP request to delete the tiddler
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "bags/" + encodeURIComponent(bag) + "/tiddlers/" + encodeURIComponent(title),
|
||||
type: "DELETE",
|
||||
callback: function(err,data,request) {
|
||||
delete self.outstandingRequests[title];
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
var revision = request.getResponseHeader("X-Revision-Number");
|
||||
// If there has been a more recent update from the server then enqueue a load of this tiddler
|
||||
self.checkLastRecordedUpdate(title,revision,options.syncer);
|
||||
self.removeTiddlerInfo(title);
|
||||
// Invoke the callback & return null adaptorInfo
|
||||
callback(null,null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if($tw.browser && document.location.protocol.substr(0,4) === "http" ) {
|
||||
exports.adaptorClass = MultiWikiClientAdaptor;
|
||||
}
|
||||
|
||||
})();
|
||||
8
plugins/tiddlywiki/multiwikiclient/plugin.info
Normal file
8
plugins/tiddlywiki/multiwikiclient/plugin.info
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "$:/plugins/tiddlywiki/multiwikiclient",
|
||||
"name": "MultiWikiClient",
|
||||
"description": "Synchronise changes from the browser to TiddlyWiki ~MultiWikiServer",
|
||||
"list": "readme",
|
||||
"plugin-priority": 10,
|
||||
"stability": "STABILITY_1_EXPERIMENTAL"
|
||||
}
|
||||
8
plugins/tiddlywiki/multiwikiclient/readme.tid
Normal file
8
plugins/tiddlywiki/multiwikiclient/readme.tid
Normal file
@@ -0,0 +1,8 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/readme
|
||||
|
||||
This plugin runs in the browser to synchronise tiddler changes to and from a TiddlyWiki server running ~MultiWikiServer.
|
||||
|
||||
|
||||
This plugin is inert when run under Node.js. Disabling this plugin via the browser can not be undone via the browser since this plugin provides the mechanism to synchronize settings with the server.
|
||||
|
||||
Changes made while offline are saved in memory and automatically synchonised with the server when the connection is re-established. However, if the browser tab is closed or another URL is loaded, the in-memory changes will be lost. The [[https://tiddlywiki.com/#BrowserStorage Plugin]] may be added to provide temporary filesystem storage of tiddler changes made while offline and enable them to be synchronised with the server the next time the wiki is loaded in the same browser.
|
||||
27
plugins/tiddlywiki/multiwikiclient/readonly-styles.tid
Normal file
27
plugins/tiddlywiki/multiwikiclient/readonly-styles.tid
Normal file
@@ -0,0 +1,27 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/readonly
|
||||
tags: [[$:/tags/Stylesheet]]
|
||||
|
||||
\define button-selector(title)
|
||||
button.$title$, .tc-drop-down button.$title$, div.$title$
|
||||
\end
|
||||
|
||||
\define hide-edit-controls()
|
||||
<$reveal state="$:/status/IsReadOnly" type="match" text="yes" default="yes">
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fclone>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fdelete>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fedit>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fnew-here>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fnew-journal-here>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fimport>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fmanager>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fnew-image>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fnew-journal>>`,`
|
||||
<<button-selector tc-btn-\%24\%3A\%2Fcore\%2Fui\%2FButtons\%2Fnew-tiddler>> `{
|
||||
display: none;
|
||||
}`
|
||||
</$reveal>
|
||||
\end
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
|
||||
|
||||
<<hide-edit-controls>>
|
||||
7
plugins/tiddlywiki/multiwikiclient/save-offline.tid
Normal file
7
plugins/tiddlywiki/multiwikiclient/save-offline.tid
Normal file
@@ -0,0 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/save/offline
|
||||
|
||||
\import [subfilter{$:/core/config/GlobalImportFilter}]
|
||||
\define saveTiddlerFilter()
|
||||
[is[tiddler]] -[[$:/boot/boot.css]] -[prefix[$:/HistoryList]] -[status[pending]plugin-type[import]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/plugins/tiddlywiki/filesystem]] -[[$:/plugins/tiddlywiki/multiwikiclient]] -[prefix[$:/temp/]] +[sort[title]] $(publishFilter)$
|
||||
\end
|
||||
{{$:/core/templates/tiddlywiki5.html}}
|
||||
26
plugins/tiddlywiki/multiwikiclient/save-wiki-button.tid
Normal file
26
plugins/tiddlywiki/multiwikiclient/save-wiki-button.tid
Normal file
@@ -0,0 +1,26 @@
|
||||
title: $:/core/ui/Buttons/save-wiki
|
||||
tags: $:/tags/PageControls
|
||||
caption: {{$:/plugins/tiddlywiki/multiwikiclient/icon/cloud}} Server status
|
||||
description: Status of synchronisation with server
|
||||
|
||||
\whitespace trim
|
||||
\define config-title()
|
||||
$:/config/PageControlButtons/Visibility/$(listItem)$
|
||||
\end
|
||||
<$button popup=<<qualify "$:/state/popup/save-wiki">> tooltip="Status of synchronisation with server" aria-label="Server status" class=<<tv-config-toolbar-class>> selectedClass="tc-selected">
|
||||
<span class="tc-dirty-indicator">
|
||||
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
|
||||
{{$:/plugins/tiddlywiki/multiwikiclient/icon/cloud}}
|
||||
</$list>
|
||||
<$list filter="[<tv-config-toolbar-text>match[yes]]">
|
||||
<span class="tc-btn-text"><$text text="Server status"/></span>
|
||||
</$list>
|
||||
</span>
|
||||
</$button>
|
||||
<$reveal state=<<qualify "$:/state/popup/save-wiki">> type="popup" position="belowleft" animate="yes">
|
||||
<div class="tc-drop-down">
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/SyncerDropdown]!has[draft.of]]" variable="listItem">
|
||||
<$transclude tiddler=<<listItem>>/>
|
||||
</$list>
|
||||
</div>
|
||||
</$reveal>
|
||||
9
plugins/tiddlywiki/multiwikiclient/sidebarsegment.tid
Normal file
9
plugins/tiddlywiki/multiwikiclient/sidebarsegment.tid
Normal file
@@ -0,0 +1,9 @@
|
||||
title: $:/plugins/multiwikiclient/SideBarSegment
|
||||
tags: $:/tags/SideBarSegment
|
||||
list-before: $:/core/ui/SideBarSegments/page-controls
|
||||
|
||||
<%if [{$:/config/multiwikiclient/use-server-sent-events}match[yes]] %>
|
||||
|
||||
MWS Connection Status: {{$:/state/multiwikiclient/connection}}
|
||||
|
||||
<%endif%>
|
||||
44
plugins/tiddlywiki/multiwikiclient/styles.tid
Normal file
44
plugins/tiddlywiki/multiwikiclient/styles.tid
Normal file
@@ -0,0 +1,44 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/styles
|
||||
tags: [[$:/tags/Stylesheet]]
|
||||
|
||||
\rules only filteredtranscludeinline transcludeinline macrodef macrocallinline macrocallblock
|
||||
|
||||
body.tc-dirty span.tc-dirty-indicator svg {
|
||||
transition: fill 250ms ease-in-out;
|
||||
}
|
||||
|
||||
body .tc-image-cloud-idle {
|
||||
fill: <<colour background>>;
|
||||
transition: opacity 250ms ease-in-out;
|
||||
opacity: 1;
|
||||
display: unset;
|
||||
}
|
||||
|
||||
body.tc-dirty .tc-image-cloud-idle {
|
||||
opacity: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
body .tc-image-cloud-progress {
|
||||
transition: opacity 250ms ease-in-out;
|
||||
transform-origin: 50% 50%;
|
||||
transform: rotate(359deg);
|
||||
animation: animation-rotate-slow 2s infinite linear;
|
||||
fill: <<colour background>>;
|
||||
display: none;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
body.tc-dirty .tc-image-cloud-progress {
|
||||
opacity: 1;
|
||||
display: unset;
|
||||
}
|
||||
|
||||
@keyframes animation-rotate-slow {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: scale(359deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/copy-logs
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$button message="tm-copy-syncer-logs-to-clipboard" class="tc-btn-invisible">
|
||||
{{$:/core/images/copy-clipboard}} Copy syncer logs to clipboard
|
||||
</$button>
|
||||
@@ -0,0 +1,9 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/login-status
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$reveal state="$:/status/IsLoggedIn" type="match" text="yes">
|
||||
<div class="tc-drop-down-info">
|
||||
You are logged in<$reveal state="$:/status/UserName" type="nomatch" text="" default=""> as <strong><$text text={{$:/status/UserName}}/></strong></$reveal><$reveal state="$:/status/IsReadOnly" type="match" text="yes" default="no"> (read-only)</$reveal>
|
||||
</div>
|
||||
<hr/>
|
||||
</$reveal>
|
||||
@@ -0,0 +1,8 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/login
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$reveal state="$:/status/IsLoggedIn" type="nomatch" text="yes">
|
||||
<$button message="tm-login" class="tc-btn-invisible">
|
||||
{{$:/core/images/unlocked-padlock}} Login
|
||||
</$button>
|
||||
</$reveal>
|
||||
@@ -0,0 +1,8 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/logout
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$reveal state="$:/status/IsLoggedIn" type="match" text="yes">
|
||||
<$button message="tm-logout" class="tc-btn-invisible">
|
||||
{{$:/core/images/cancel-button}} Logout
|
||||
</$button>
|
||||
</$reveal>
|
||||
@@ -0,0 +1,9 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/refresh
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$reveal state="$:/status/IsLoggedIn" type="match" text="yes">
|
||||
<$button tooltip="Get latest changes from the server" aria-label="Refresh from server" class="tc-btn-invisible">
|
||||
<$action-sendmessage $message="tm-server-refresh"/>
|
||||
{{$:/core/images/refresh-button}}<span class="tc-btn-text"><$text text="Get latest changes from the server"/></span>
|
||||
</$button>
|
||||
</$reveal>
|
||||
@@ -0,0 +1,9 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/save-snapshot
|
||||
tags: $:/tags/SyncerDropdown
|
||||
|
||||
<$button class="tc-btn-invisible">
|
||||
<$wikify name="site-title" text={{$:/config/SaveWikiButton/Filename}}>
|
||||
<$action-sendmessage $message="tm-download-file" $param={{$:/config/SaveWikiButton/Template}} filename=<<site-title>>/>
|
||||
</$wikify>
|
||||
{{$:/core/images/download-button}} Save snapshot for offline use
|
||||
</$button>
|
||||
@@ -0,0 +1,2 @@
|
||||
title: $:/tags/SyncerDropdown
|
||||
list: $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/login-status $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/login $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/refresh $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/logout $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/save-snapshot $:/plugins/tiddlywiki/multiwikiclient/syncer-actions/copy-logs
|
||||
43
plugins/tiddlywiki/multiwikiserver/auth/authentication.js
Normal file
43
plugins/tiddlywiki/multiwikiserver/auth/authentication.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/auth/authentication.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Handles authentication related operations
|
||||
|
||||
\*/
|
||||
|
||||
(function() {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var crypto = require("crypto");
|
||||
|
||||
function Authenticator(database) {
|
||||
if(!(this instanceof Authenticator)) {
|
||||
return new Authenticator(database);
|
||||
}
|
||||
this.sqlTiddlerDatabase = database;
|
||||
}
|
||||
|
||||
Authenticator.prototype.verifyPassword = function(inputPassword, storedHash) {
|
||||
var hashedInput = this.hashPassword(inputPassword);
|
||||
return hashedInput === storedHash;
|
||||
};
|
||||
|
||||
Authenticator.prototype.hashPassword = function(password) {
|
||||
return crypto.createHash("sha256").update(password).digest("hex");
|
||||
};
|
||||
|
||||
Authenticator.prototype.createSession = function(userId) {
|
||||
var sessionId = crypto.randomBytes(16).toString("hex");
|
||||
// Store the session in your database or in-memory store
|
||||
this.sqlTiddlerDatabase.createOrUpdateUserSession(userId, sessionId);
|
||||
return sessionId;
|
||||
};
|
||||
|
||||
exports.Authenticator = Authenticator;
|
||||
|
||||
})();
|
||||
19
plugins/tiddlywiki/multiwikiserver/auth/form/login.tid
Normal file
19
plugins/tiddlywiki/multiwikiserver/auth/form/login.tid
Normal file
@@ -0,0 +1,19 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login
|
||||
tags: $:/tags/ServerRoute
|
||||
route-method: GET
|
||||
route-path: /login
|
||||
|
||||
<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/styles"/>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/head"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/header" mode="block"/>
|
||||
<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/form" mode="block"/>
|
||||
<$transclude tiddler="$:/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message" mode="block"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/auth/form/login/error-message
|
||||
|
||||
<$list filter="[[$:/temp/mws/login/error]!is[missing]]" variable="errorTiddler">
|
||||
<div class="tc-error-message">
|
||||
{{$:/temp/mws/login/error}}
|
||||
</div>
|
||||
</$list>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user