mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-05 01:26:18 +00:00
Introduce multiwikiclient plugin
Routes are now rationalised, too.
This commit is contained in:
parent
38ee942d8f
commit
9b3ca525ee
@ -3,6 +3,7 @@
|
||||
"plugins": [
|
||||
"tiddlywiki/tiddlyweb",
|
||||
"tiddlywiki/filesystem",
|
||||
"tiddlywiki/multiwikiclient",
|
||||
"tiddlywiki/multiwikiserver"
|
||||
],
|
||||
"themes": [
|
||||
|
16
plugins/tiddlywiki/multiwikiclient/GettingStarted.tid
Normal file
16
plugins/tiddlywiki/multiwikiclient/GettingStarted.tid
Normal file
@ -0,0 +1,16 @@
|
||||
title: GettingStarted
|
||||
tags: $:/tags/GettingStarted
|
||||
caption: Step 1<br>Syncing
|
||||
|
||||
Welcome to ~TiddlyWiki and the ~TiddlyWiki community
|
||||
|
||||
Visit https://tiddlywiki.com/ to find out more about ~TiddlyWiki and what it can do.
|
||||
|
||||
! Syncing Changes to the Server
|
||||
|
||||
Before you can start storing important information in ~TiddlyWiki it is important to make sure that your changes are being reliably saved by the server.
|
||||
|
||||
# Create a new tiddler using the {{$:/core/images/new-button}} button in the sidebar on the right
|
||||
# Click the {{$:/core/images/done-button}} button at the top right of the new tiddler
|
||||
# Check the ~TiddlyWiki command line for a message confirming the tiddler has been saved
|
||||
# Refresh the page in the browser to and verify that the new tiddler has been correctly saved
|
@ -0,0 +1,3 @@
|
||||
title: $:/config/SaveWikiButton/Template
|
||||
|
||||
$:/plugins/tiddlywiki/multiwikiclient/save/offline
|
@ -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,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]].
|
7
plugins/tiddlywiki/multiwikiclient/css-tiddler.tid
Normal file
7
plugins/tiddlywiki/multiwikiclient/css-tiddler.tid
Normal file
@ -0,0 +1,7 @@
|
||||
title: $:/core/templates/css-tiddler
|
||||
|
||||
<!--
|
||||
|
||||
This template is used for saving CSS tiddlers as a style tag with data attributes representing the tiddler fields. This version includes the tiddler changecount as the field `revision`.
|
||||
|
||||
-->`<style`<$fields exclude='text revision bag' template=' data-tiddler-$name$="$encoded_value$"'></$fields>` data-tiddler-revision="`<<changecount>>`" data-tiddler-bag="default" type="text/css">`<$view field="text" format="text" />`</style>`
|
@ -0,0 +1,9 @@
|
||||
title: $:/core/templates/html-div-skinny-tiddler
|
||||
|
||||
<!--
|
||||
|
||||
This template is a variant of the tiddlyweb plugin's overridden version of $:/core/templates/html-div-tiddler used for saving skinny tiddlers (with no text field)
|
||||
|
||||
-->`<div`<$fields exclude='text revision bag' template=' $name$="$encoded_value$"'></$fields>` revision="`<<changecount>>`" bag="default" _is_skinny="">
|
||||
<pre></pre>
|
||||
</div>`
|
9
plugins/tiddlywiki/multiwikiclient/html-div-tiddler.tid
Normal file
9
plugins/tiddlywiki/multiwikiclient/html-div-tiddler.tid
Normal file
@ -0,0 +1,9 @@
|
||||
title: $:/core/templates/html-div-tiddler
|
||||
|
||||
<!--
|
||||
|
||||
This template is used for saving tiddlers as an HTML DIV tag with attributes representing the tiddler fields. This version includes the tiddler changecount as the field `revision`.
|
||||
|
||||
-->`<div`<$fields exclude='text revision bag' template=' $name$="$encoded_value$"'></$fields>` revision="`<<changecount>>`" bag="default">
|
||||
<pre>`<$view field="text" format="htmltextencoded" />`</pre>
|
||||
</div>`
|
@ -0,0 +1,3 @@
|
||||
title: $:/core/templates/html-json-skinny-tiddler
|
||||
|
||||
<$text text=<<join>>/><$jsontiddler tiddler=<<currentTiddler>> exclude="text" escapeUnsafeScriptChars="yes" $revision=<<changecount>> $bag="default" $_is_skinny=""/>
|
3
plugins/tiddlywiki/multiwikiclient/html-json-tiddler.tid
Normal file
3
plugins/tiddlywiki/multiwikiclient/html-json-tiddler.tid
Normal file
@ -0,0 +1,3 @@
|
||||
title: $:/core/templates/html-json-tiddler
|
||||
|
||||
<$jsontiddler tiddler=<<currentTiddler>> escapeUnsafeScriptChars="yes" $revision=<<changecount>> $bag="default"/>
|
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>
|
@ -0,0 +1,7 @@
|
||||
title: $:/core/templates/javascript-tiddler
|
||||
|
||||
<!--
|
||||
|
||||
This template is used for saving JavaScript tiddlers as a script tag with data attributes representing the tiddler fields. This version includes the tiddler changecount as the field `revision`.
|
||||
|
||||
-->`<script`<$fields exclude='text revision bag' template=' data-tiddler-$name$="$encoded_value$"'></$fields>` data-tiddler-revision="`<<changecount>>`" data-tiddler-bag="default" type="text/javascript">`<$view field="text" format="text" />`</script>`
|
351
plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
Normal file
351
plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
Normal file
@ -0,0 +1,351 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiclient/multiwikiclientadaptor.js
|
||||
type: application/javascript
|
||||
module-type: syncadaptor
|
||||
|
||||
A sync adaptor module for synchronising with MultiWikiServer-compatible servers
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
var CONFIG_HOST_TIDDLER = "$:/config/multiwikiclient/host",
|
||||
DEFAULT_HOST_TIDDLER = "$protocol$//$host$/";
|
||||
|
||||
function MultiWikiClientAdaptor(options) {
|
||||
this.wiki = options.wiki;
|
||||
this.host = this.getHost();
|
||||
this.recipe = this.wiki.getTiddlerText("$:/config/multiwikiclient/recipe");
|
||||
this.logger = new $tw.utils.Logger("MultiWikiClientAdaptor");
|
||||
this.isLoggedIn = false;
|
||||
this.isReadOnly = false;
|
||||
this.logoutIsAvailable = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
return {
|
||||
bag: tiddler.fields.bag
|
||||
};
|
||||
};
|
||||
|
||||
MultiWikiClientAdaptor.prototype.getTiddlerRevision = function(title) {
|
||||
var tiddler = this.wiki.getTiddler(title);
|
||||
return tiddler.fields.revision;
|
||||
};
|
||||
|
||||
/*
|
||||
Get the current status of the TiddlyWeb 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
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Attempt to login and invoke the callback(err)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.login = function(username,password,callback) {
|
||||
var options = {
|
||||
url: this.host + "challenge/tiddlywebplugins.tiddlyspace.cookie_form",
|
||||
type: "POST",
|
||||
data: {
|
||||
user: username,
|
||||
password: password,
|
||||
tiddlyweb_redirect: "/status" // workaround to marginalize automatic subsequent GET
|
||||
},
|
||||
callback: function(err) {
|
||||
callback(err);
|
||||
},
|
||||
headers: {
|
||||
"accept": "application/json",
|
||||
"X-Requested-With": "TiddlyWiki"
|
||||
}
|
||||
};
|
||||
this.logger.log("Logging in:",options);
|
||||
$tw.utils.httpRequest(options);
|
||||
};
|
||||
|
||||
/*
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.logout = function(callback) {
|
||||
if(this.logoutIsAvailable) {
|
||||
var options = {
|
||||
url: this.host + "logout",
|
||||
type: "POST",
|
||||
data: {
|
||||
csrf_token: this.getCsrfToken(),
|
||||
tiddlyweb_redirect: "/status" // workaround to marginalize automatic subsequent GET
|
||||
},
|
||||
callback: function(err,data,xhr) {
|
||||
callback(err);
|
||||
},
|
||||
headers: {
|
||||
"accept": "application/json",
|
||||
"X-Requested-With": "TiddlyWiki"
|
||||
}
|
||||
};
|
||||
this.logger.log("Logging out:",options);
|
||||
$tw.utils.httpRequest(options);
|
||||
} else {
|
||||
alert("This server does not support logging out. If you are using basic authentication the only way to logout is close all browser windows");
|
||||
callback(null);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Retrieve the CSRF token from its cookie
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.getCsrfToken = function() {
|
||||
var regex = /^(?:.*; )?csrf_token=([^(;|$)]*)(?:;|$)/,
|
||||
match = regex.exec(document.cookie),
|
||||
csrf = null;
|
||||
if (match && (match.length === 2)) {
|
||||
csrf = match[1];
|
||||
}
|
||||
return csrf;
|
||||
};
|
||||
|
||||
/*
|
||||
Get an array of skinny tiddler fields from the server
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.getSkinnyTiddlers = function(callback) {
|
||||
var self = this;
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + this.recipe + "/tiddlers.json",
|
||||
data: {
|
||||
filter: "[all[tiddlers]] -[[$:/isEncrypted]] -[prefix[$:/temp/]] -[prefix[$:/status/]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/library/sjcl.js]] -[[$:/core]]"
|
||||
},
|
||||
callback: function(err,data) {
|
||||
// Check for errors
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
// Process the tiddlers to make sure the revision is a string
|
||||
var tiddlers = JSON.parse(data);
|
||||
for(var t=0; t<tiddlers.length; t++) {
|
||||
tiddlers[t] = self.convertTiddlerFromTiddlyWebFormat(tiddlers[t]);
|
||||
}
|
||||
// Invoke the callback with the skinny tiddlers
|
||||
callback(null,tiddlers);
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.saveTiddler = function(tiddler,callback,options) {
|
||||
var self = this;
|
||||
if(this.isReadOnly) {
|
||||
return callback(null);
|
||||
}
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + encodeURIComponent(this.recipe) + "/tiddlers/" + encodeURIComponent(tiddler.fields.title),
|
||||
type: "PUT",
|
||||
headers: {
|
||||
"Content-type": "application/json"
|
||||
},
|
||||
data: this.convertTiddlerToTiddlyWebFormat(tiddler),
|
||||
callback: function(err,data,request) {
|
||||
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(tiddler.fields.title)
|
||||
}
|
||||
// Save the details of the new revision of the tiddler
|
||||
var etag = request.getResponseHeader("Etag");
|
||||
if(!etag) {
|
||||
callback("Response from server is missing required `etag` header");
|
||||
} else {
|
||||
var etagInfo = self.parseEtag(etag);
|
||||
// Invoke the callback
|
||||
callback(null,{
|
||||
bag: etagInfo.bag
|
||||
},etagInfo.revision);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Load a tiddler and invoke the callback with (err,tiddlerFields)
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.loadTiddler = function(title,callback) {
|
||||
var self = this;
|
||||
$tw.utils.httpRequest({
|
||||
url: this.host + "recipes/" + encodeURIComponent(this.recipe) + "/tiddlers/" + encodeURIComponent(title),
|
||||
callback: function(err,data,request) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
// Invoke the callback
|
||||
callback(null,self.convertTiddlerFromTiddlyWebFormat(JSON.parse(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 = options.tiddlerInfo.adaptorInfo && options.tiddlerInfo.adaptorInfo.bag;
|
||||
if(!bag) {
|
||||
return callback(null,options.tiddlerInfo.adaptorInfo);
|
||||
}
|
||||
// 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) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
// Invoke the callback & return null adaptorInfo
|
||||
callback(null,null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a tiddler to a field set suitable for PUTting to TiddlyWeb
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.convertTiddlerToTiddlyWebFormat = function(tiddler) {
|
||||
var result = {},
|
||||
knownFields = [
|
||||
"bag", "created", "creator", "modified", "modifier", "permissions", "recipe", "revision", "tags", "text", "title", "type", "uri"
|
||||
];
|
||||
if(tiddler) {
|
||||
$tw.utils.each(tiddler.fields,function(fieldValue,fieldName) {
|
||||
var fieldString = fieldName === "tags" ?
|
||||
tiddler.fields.tags :
|
||||
tiddler.getFieldString(fieldName); // Tags must be passed as an array, not a string
|
||||
|
||||
if(knownFields.indexOf(fieldName) !== -1) {
|
||||
// If it's a known field, just copy it across
|
||||
result[fieldName] = fieldString;
|
||||
} else {
|
||||
// If it's unknown, put it in the "fields" field
|
||||
result.fields = result.fields || {};
|
||||
result.fields[fieldName] = fieldString;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Default the content type
|
||||
result.type = result.type || "text/vnd.tiddlywiki";
|
||||
return JSON.stringify(result,null,$tw.config.preferences.jsonSpaces);
|
||||
};
|
||||
|
||||
/*
|
||||
Convert a field set in TiddlyWeb format into ordinary TiddlyWiki5 format
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.convertTiddlerFromTiddlyWebFormat = function(tiddlerFields) {
|
||||
var self = this,
|
||||
result = {};
|
||||
// Transfer the fields, pulling down the `fields` hashmap
|
||||
$tw.utils.each(tiddlerFields,function(element,title,object) {
|
||||
if(title === "fields") {
|
||||
$tw.utils.each(element,function(element,subTitle,object) {
|
||||
result[subTitle] = element;
|
||||
});
|
||||
} else {
|
||||
result[title] = tiddlerFields[title];
|
||||
}
|
||||
});
|
||||
// Make sure the revision is expressed as a string
|
||||
if(typeof result.revision === "number") {
|
||||
result.revision = result.revision.toString();
|
||||
}
|
||||
// Some unholy freaking of content types
|
||||
if(result.type === "text/javascript") {
|
||||
result.type = "application/javascript";
|
||||
} else if(!result.type || result.type === "None") {
|
||||
result.type = "text/x-tiddlywiki";
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
Split a TiddlyWeb Etag into its constituent parts. For example:
|
||||
|
||||
```
|
||||
"system-images_public/unsyncedIcon/946151:9f11c278ccde3a3149f339f4a1db80dd4369fc04"
|
||||
```
|
||||
|
||||
Note that the value includes the opening and closing double quotes.
|
||||
|
||||
The parts are:
|
||||
|
||||
```
|
||||
<bag>/<title>/<revision>:<hash>
|
||||
```
|
||||
*/
|
||||
MultiWikiClientAdaptor.prototype.parseEtag = function(etag) {
|
||||
var firstSlash = etag.indexOf("/"),
|
||||
lastSlash = etag.lastIndexOf("/"),
|
||||
colon = etag.lastIndexOf(":");
|
||||
if(firstSlash === -1 || lastSlash === -1 || colon === -1) {
|
||||
return null;
|
||||
} else {
|
||||
return {
|
||||
bag: $tw.utils.decodeURIComponentSafe(etag.substring(1,firstSlash)),
|
||||
title: $tw.utils.decodeURIComponentSafe(etag.substring(firstSlash + 1,lastSlash)),
|
||||
revision: etag.substring(lastSlash + 1,colon)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
if($tw.browser && document.location.protocol.substr(0,4) === "http" ) {
|
||||
exports.adaptorClass = MultiWikiClientAdaptor;
|
||||
}
|
||||
|
||||
})();
|
7
plugins/tiddlywiki/multiwikiclient/plugin.info
Normal file
7
plugins/tiddlywiki/multiwikiclient/plugin.info
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"title": "$:/plugins/tiddlywiki/multiwikiclient",
|
||||
"name": "MultiWikiClient",
|
||||
"description": "Synchronise changes from the browser to TiddlyWiki ~MultiWikiServer",
|
||||
"list": "readme",
|
||||
"plugin-priority": 10
|
||||
}
|
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>
|
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
|
@ -113,14 +113,15 @@ TestRunner.prototype.runTest = function(testSpec,callback) {
|
||||
|
||||
const testSpecs = [
|
||||
{
|
||||
description: "Check server status",
|
||||
description: "Check index page",
|
||||
method: "GET",
|
||||
path: "/wiki/recipe-alpha/status",
|
||||
path: "/",
|
||||
headers: {
|
||||
accept: "*/*"
|
||||
},
|
||||
expectedResult: (jsonData,data) => {
|
||||
return jsonData.username === "Joe Bloggs";
|
||||
expectedResult: (jsonData,data,headers) => {
|
||||
console.log(JSON.stringify(data).slice(1,100))
|
||||
return JSON.stringify(data).slice(1,100) === "\\n<!doctype html>\\n<head>\\n\\t<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html;charset=utf-8\\\" ";
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/delete-bag-tiddler.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
DELETE /bags/:bag_name/tiddler/:title
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.method = "DELETE";
|
||||
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
if(bag_name) {
|
||||
$tw.mws.store.deleteTiddler(title,bag_name);
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
@ -1,39 +0,0 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/delete-recipe-tiddler.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
DELETE /wiki/:recipe_name/recipes/:bag_name/tiddler/:title
|
||||
|
||||
NOTE: Urls currently include the recipe name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.method = "DELETE";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[2]);
|
||||
var recipeBags = $tw.mws.store.getRecipeBags(recipe_name);
|
||||
if(recipeBags.indexOf(bag_name) !== -1) {
|
||||
$tw.mws.store.deleteTiddler(title,bag_name);
|
||||
response.writeHead(204, "OK", {
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
response.end();
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
@ -3,7 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-bag-tiddler-blo
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:bag_name/bags/:bag_name/tiddler/:title/blob
|
||||
GET /bags/:bag_name/tiddler/:title/blob
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -14,14 +14,13 @@ GET /wiki/:bag_name/bags/:bag_name/tiddler/:title/blob
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/([^\/]+)\/tiddlers\/([^\/]+)\/blob$/;
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/([^\/]+)\/blob$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
const bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[2]);
|
||||
if(bag_name === bag_name_2) {
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
if(bag_name) {
|
||||
const result = $tw.mws.store.getBagTiddlerStream(title,bag_name);
|
||||
if(result) {
|
||||
response.writeHead(200, "OK",{
|
||||
|
@ -3,9 +3,8 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-bag-tiddler.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:bag_name/bags/:bag_name/tiddler/:title
|
||||
GET /bags/:bag_name/tiddler/:title
|
||||
|
||||
NOTE: Urls currently include the bag name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,15 +15,14 @@ NOTE: Urls currently include the bag name twice. This is temporary to minimise t
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[2]),
|
||||
result = bag_name === bag_name_2 && $tw.mws.store.getBagTiddler(title,bag_name);
|
||||
if(bag_name === bag_name_2 && result) {
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
result = bag_name && $tw.mws.store.getBagTiddler(title,bag_name);
|
||||
if(bag_name && result) {
|
||||
// If application/json is requested then this is an API request, and gets the response in JSON
|
||||
if(request.headers.accept && request.headers.accept.indexOf("application/json") !== -1) {
|
||||
var tiddlerFields = {},
|
||||
|
@ -3,10 +3,8 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-bag.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:bag_name/bags/:bag_name/
|
||||
GET /wiki/:bag_name/bags/:bag_name
|
||||
|
||||
NOTE: Urls currently include the bag name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
GET /bags/:bag_name/
|
||||
GET /bags/:bag_name
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -17,19 +15,18 @@ NOTE: Urls currently include the bag name twice. This is temporary to minimise t
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/([^\/]+)(\/?)$/;
|
||||
exports.path = /^\/bags\/([^\/]+)(\/?)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Redirect if there is no trailing slash. We do this so that the relative URL specified in the upload form works correctly
|
||||
if(state.params[2] !== "/") {
|
||||
if(state.params[1] !== "/") {
|
||||
state.redirect(301,state.urlInfo.path + "/");
|
||||
return;
|
||||
}
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
bagTiddlers = bag_name === bag_name_2 && $tw.mws.store.getBagTiddlers(bag_name);
|
||||
if(bag_name === bag_name_2 && bagTiddlers) {
|
||||
bagTiddlers = bag_name && $tw.mws.store.getBagTiddlers(bag_name);
|
||||
if(bag_name && bagTiddlers) {
|
||||
// If application/json is requested then this is an API request, and gets the response in JSON
|
||||
if(request.headers.accept && request.headers.accept.indexOf("application/json") !== -1) {
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},JSON.stringify(bagTiddlers),"utf8");
|
||||
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-recipe-tiddler.
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:recipe_name/recipes/:recipe_name/tiddler/:title
|
||||
|
||||
NOTE: Urls currently include the recipe name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
GET /recipes/:recipe_name/tiddler/:title
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,15 +14,14 @@ NOTE: Urls currently include the recipe name twice. This is temporary to minimis
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/recipes\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
exports.path = /^\/recipes\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
recipe_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[2]),
|
||||
tiddlerInfo = recipe_name === recipe_name_2 && $tw.mws.store.getRecipeTiddler(title,recipe_name);
|
||||
if(recipe_name === recipe_name_2 && tiddlerInfo && tiddlerInfo.tiddler) {
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
tiddlerInfo = recipe_name && $tw.mws.store.getRecipeTiddler(title,recipe_name);
|
||||
if(recipe_name && tiddlerInfo && tiddlerInfo.tiddler) {
|
||||
// If application/json is requested then this is an API request, and gets the response in JSON
|
||||
if(request.headers.accept && request.headers.accept.indexOf("application/json") !== -1) {
|
||||
var tiddlerFields = {},
|
||||
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-recipe-tiddlers
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:recipe_name/recipes/:recipe_name/tiddlers.json?filter=:filter
|
||||
|
||||
NOTE: Urls currently include the recipe name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
GET /recipes/:recipe_name/tiddlers.json?filter=:filter
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,13 +14,12 @@ NOTE: Urls currently include the recipe name twice. This is temporary to minimis
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/recipes\/([^\/]+)\/tiddlers.json$/;
|
||||
exports.path = /^\/recipes\/([^\/]+)\/tiddlers.json$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
recipe_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
if(recipe_name === recipe_name_2) {
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
if(recipe_name) {
|
||||
// Get the tiddlers in the recipe
|
||||
var recipeTiddlers = $tw.mws.store.getRecipeTiddlers(recipe_name);
|
||||
// Get a skinny version of each tiddler
|
||||
|
@ -36,7 +36,7 @@ exports.handler = function(request,response,state) {
|
||||
$:/boot/bootprefix.js
|
||||
$:/core
|
||||
$:/library/sjcl.js
|
||||
$:/plugins/tiddlywiki/tiddlyweb
|
||||
$:/plugins/tiddlywiki/multiwikiclient
|
||||
$:/themes/tiddlywiki/snowwhite
|
||||
$:/themes/tiddlywiki/vanilla
|
||||
`
|
||||
@ -57,7 +57,7 @@ exports.handler = function(request,response,state) {
|
||||
response.write(",\n")
|
||||
}
|
||||
});
|
||||
response.write(JSON.stringify({title: "$:/config/tiddlyweb/host",text: "$protocol$//$host$$pathname$/"}));
|
||||
response.write(JSON.stringify({title: "$:/config/multiwikiclient/recipe",text: recipe_name}));
|
||||
response.write(",\n")
|
||||
response.write(template.substring(markerPos + marker.length))
|
||||
// Finish response
|
||||
|
@ -1,42 +0,0 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/get-status.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
GET /wiki/:recipe_name/status
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
exports.method = "GET";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/status$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the recipe name from the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
// Compose the response
|
||||
var text = JSON.stringify({
|
||||
username: "Joe Bloggs",
|
||||
anonymous: false,
|
||||
read_only: false,
|
||||
logout_is_available: false,
|
||||
space: {
|
||||
recipe: recipe_name
|
||||
},
|
||||
tiddlywiki_version: $tw.version
|
||||
});
|
||||
// Send response
|
||||
if(text) {
|
||||
state.sendResponse(200,{"Content-Type": "application/json"},text,"utf8");
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/post-bag-tiddlers.j
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
POST /wiki/:bag_name/bags/:bag_name/tiddlers/
|
||||
|
||||
NOTE: Urls currently include the bag name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
POST /bags/:bag_name/tiddlers/
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,7 +14,7 @@ NOTE: Urls currently include the bag name twice. This is temporary to minimise t
|
||||
|
||||
exports.method = "POST";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/([^\/]+)\/tiddlers\/$/;
|
||||
exports.path = /^\/bags\/([^\/]+)\/tiddlers\/$/;
|
||||
|
||||
exports.bodyFormat = "stream";
|
||||
|
||||
@ -27,12 +25,7 @@ exports.handler = function(request,response,state) {
|
||||
fs = require("fs"),
|
||||
processIncomingStream = require("$:/plugins/tiddlywiki/multiwikiserver/routes/helpers/multipart-forms.js").processIncomingStream;
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]);
|
||||
// Require the bag names to match
|
||||
if(bag_name !== bag_name_2) {
|
||||
return state.sendResponse(400,{"Content-Type": "text/plain"},"Bad Request: bag names do not match");
|
||||
}
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]);
|
||||
// Process the incoming data
|
||||
processIncomingStream({
|
||||
store: $tw.mws.store,
|
||||
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/put-bag.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
PUT /wiki/:bag_name/bags/:bag_name
|
||||
|
||||
NOTE: Urls currently include the bag name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
PUT /bags/:bag_name
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,14 +14,13 @@ NOTE: Urls currently include the bag name twice. This is temporary to minimise t
|
||||
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/bags\/(.+)$/;
|
||||
exports.path = /^\/bags\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var bag_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
bag_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
data = $tw.utils.parseJSONSafe(state.data);
|
||||
if(bag_name === bag_name_2 && data) {
|
||||
if(bag_name && data) {
|
||||
const result = $tw.mws.store.createBag(bag_name,data.description);
|
||||
if(!result) {
|
||||
state.sendResponse(204,{
|
||||
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/put-recipe-tiddler.
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
PUT /wiki/:recipe_name/recipes/:recipe_name/tiddlers/:title
|
||||
|
||||
NOTE: Urls currently include the recipe name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
PUT /recipes/:recipe_name/tiddlers/:title
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,13 +14,12 @@ NOTE: Urls currently include the recipe name twice. This is temporary to minimis
|
||||
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/recipes\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
exports.path = /^\/recipes\/([^\/]+)\/tiddlers\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
recipe_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[2]),
|
||||
title = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
fields = $tw.utils.parseJSONSafe(state.data);
|
||||
// Pull up any subfields in the `fields` object
|
||||
if(typeof fields.fields === "object") {
|
||||
@ -37,8 +34,7 @@ exports.handler = function(request,response,state) {
|
||||
fields[name] = $tw.utils.stringifyList(value);
|
||||
}
|
||||
});
|
||||
// Require the recipe names to match
|
||||
if(recipe_name === recipe_name_2) {
|
||||
if(recipe_name) {
|
||||
var result = $tw.mws.store.saveRecipeTiddler(fields,recipe_name);
|
||||
if(result) {
|
||||
response.writeHead(204, "OK",{
|
||||
|
@ -3,9 +3,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/routes/handlers/put-recipe.js
|
||||
type: application/javascript
|
||||
module-type: mws-route
|
||||
|
||||
PUT /wiki/:recipe_name/recipes/:recipe_name
|
||||
|
||||
NOTE: Urls currently include the recipe name twice. This is temporary to minimise the changes to the TiddlyWeb plugin
|
||||
PUT /recipes/:recipe_name
|
||||
|
||||
\*/
|
||||
(function() {
|
||||
@ -16,14 +14,13 @@ NOTE: Urls currently include the recipe name twice. This is temporary to minimis
|
||||
|
||||
exports.method = "PUT";
|
||||
|
||||
exports.path = /^\/wiki\/([^\/]+)\/recipes\/(.+)$/;
|
||||
exports.path = /^\/recipes\/(.+)$/;
|
||||
|
||||
exports.handler = function(request,response,state) {
|
||||
// Get the parameters
|
||||
var recipe_name = $tw.utils.decodeURIComponentSafe(state.params[0]),
|
||||
recipe_name_2 = $tw.utils.decodeURIComponentSafe(state.params[1]),
|
||||
data = $tw.utils.parseJSONSafe(state.data);
|
||||
if(recipe_name === recipe_name_2 && data) {
|
||||
if(recipe_name && data) {
|
||||
const result = $tw.mws.store.createRecipe(recipe_name,data.bag_names,data.description);
|
||||
if(!result) {
|
||||
state.sendResponse(204,{
|
||||
|
@ -92,7 +92,7 @@ SqlTiddlerStore.prototype.processOutgoingTiddler = function(tiddlerFields,tiddle
|
||||
});
|
||||
if(attachment_blob !== null) {
|
||||
delete fields.text;
|
||||
fields._canonical_uri = `/wiki/${encodeURIComponent(bag_name)}/bags/${encodeURIComponent(bag_name)}/tiddlers/${encodeURIComponent(tiddlerFields.title)}/blob`;
|
||||
fields._canonical_uri = `/bags/${encodeURIComponent(bag_name)}/tiddlers/${encodeURIComponent(tiddlerFields.title)}/blob`;
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
@ -98,11 +98,6 @@ body {
|
||||
color: currentcolor;
|
||||
}
|
||||
|
||||
.mws-favicon.tc-image-loading, .mws-favicon-small.tc-image-loading,
|
||||
.mws-favicon.tc-image-error, .mws-favicon-small.tc-image-error {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.mws-favicon {
|
||||
object-fit: contain;
|
||||
width: 4em;
|
||||
|
@ -1,7 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-bag
|
||||
|
||||
! <$image
|
||||
source=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
source=`/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
class="mws-favicon-small"
|
||||
width="32px"
|
||||
>
|
||||
@ -43,7 +43,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-bag
|
||||
<ul>
|
||||
<$list filter="[<bag-titles>jsonget[]sort[]]">
|
||||
<li>
|
||||
<a href=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/${ [<currentTiddler>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<a href=`/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/${ [<currentTiddler>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</a>
|
||||
</li>
|
||||
|
@ -3,9 +3,9 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
|
||||
\procedure bagPill(element-tag:"span",is-topmost:"no")
|
||||
\whitespace trim
|
||||
<$genesis $type=<<element-tag>> class={{{ mws-bag-pill [<is-topmost>match[yes]then[mws-bag-pill-topmost]] +[join[ ]] }}}>
|
||||
<a class="mws-bag-pill-link" href=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<a class="mws-bag-pill-link" href=`/bags/${ [<bag-name>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<img
|
||||
src=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
src=`/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
class="mws-favicon-small"
|
||||
/>
|
||||
<span class="mws-bag-pill-label">
|
||||
@ -29,7 +29,7 @@ title: $:/plugins/tiddlywiki/multiwikiserver/templates/get-index
|
||||
>
|
||||
<div class="mws-wiki-card-image">
|
||||
<img
|
||||
src=`/wiki/${ [<recipe-name>encodeuricomponent[]] }$/recipes/${ [<recipe-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
src=`/recipes/${ [<recipe-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
class="mws-favicon"
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/multiwikiserver/templates/post-bag-tiddlers
|
||||
|
||||
! <$image
|
||||
source=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
source=`/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/%24%3A%2Ffavicon.ico`
|
||||
class="mws-favicon-small"
|
||||
width="32px"
|
||||
>
|
||||
@ -23,7 +23,7 @@ The following tiddlers were successfully imported:
|
||||
<ul>
|
||||
<$list filter="[<imported-titles>jsonget[]sort[]]">
|
||||
<li>
|
||||
<a href=`/wiki/${ [<bag-name>encodeuricomponent[]] }$/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/${ [<currentTiddler>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<a href=`/bags/${ [<bag-name>encodeuricomponent[]] }$/tiddlers/${ [<currentTiddler>encodeuricomponent[]] }$` rel="noopener noreferrer" target="_blank">
|
||||
<$text text=<<currentTiddler>>/>
|
||||
</a>
|
||||
</li>
|
||||
|
Loading…
Reference in New Issue
Block a user