This commit is contained in:
Sebastian Silva 2024-03-29 16:55:41 -07:00 committed by GitHub
commit a569c7767d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 350 additions and 3 deletions

View File

@ -283,7 +283,7 @@ exports.httpRequest = function(options) {
// Set up the state change handler
request.onreadystatechange = function() {
if(this.readyState === 4) {
if(this.status === 200 || this.status === 201 || this.status === 204) {
if(this.status === 200 || this.status === 201 || this.status === 204 || this.status === 207) {
// Success!
options.callback(null,this[returnProp],this);
return;

View File

@ -1,7 +1,8 @@
{
"description": "Base edition for TiddlySpace integration",
"plugins": [
"tiddlywiki/tiddlyweb"
"tiddlywiki/tiddlyweb",
"tiddlywiki/filesystem"
],
"themes": [
"tiddlywiki/vanilla",
@ -11,4 +12,4 @@
"index": [
"--rendertiddler","$:/core/save/all","tw5tiddlyweb.html","text/plain"]
}
}
}

View File

@ -0,0 +1,3 @@
title: TiddlerListTemplate
<$view field="title" format="link"/> <small><$view field="type"/></small>

View File

@ -0,0 +1,15 @@
title: WebDAV sync adaptor plugin
created: 201311152153
modified: 201805170313
! Features
* Loads skinny tiddlers from entire shared directory at startup/login
* Subsequently syncs changes back to the server
* Polls for changes from the server
! Issues
* ''[[$:/DefaultTiddlers]]'' doesn't work because thanks to lazy loading it is only loaded after it is needed
* Should probably disable PUT saver
* Ignores ''if-match'' header, so doesn't detect clashes on save

View File

@ -0,0 +1,3 @@
title: $:/DefaultTiddlers
[[WebDAV sync adaptor plugin]]

View File

@ -0,0 +1,3 @@
title: $:/SiteSubtitle
for TiddlyWiki

View File

@ -0,0 +1,3 @@
title: $:/SiteTitle
TiddlyWiki in the Sky (WebDAV)

View File

@ -0,0 +1,14 @@
{
"description": "Base edition for WebDAV integration",
"plugins": [
"tiddlywiki/webdav"
],
"themes": [
"tiddlywiki/vanilla",
"tiddlywiki/snowwhite"
],
"build": {
"index": [
"--rendertiddler","$:/core/save/all","tiddlywebdav.html","text/plain"]
}
}

View 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

View File

@ -0,0 +1,3 @@
title: $:/config/SaveWikiButton/Template
$:/plugins/tiddlywiki/webdav/save/offline

View File

@ -0,0 +1,11 @@
title: $:/plugins/tiddlywiki/webdav/ServerControlPanel
caption: Server
tags: $:/tags/ControlPanel
Host configuration: <$edit-text tiddler="$:/config/webdav/host" tag="input" default=""/>
<blockquote>//for example, `$protocol$//$host$/folder`, where `$protocol$` is replaced by the protocol (typically `http` or `https`), and `$host$` by the host name//</blockquote>
----
<$button message="tm-server-refresh">Refresh</$button> to fetch changes from the server immediately

View 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="htmlencoded" />`</pre>
</div>`

View File

@ -0,0 +1,7 @@
{
"title": "$:/plugins/tiddlywiki/webdav",
"description": "WebDAV sync adaptor",
"author": "Sebastian Silva",
"core-version": ">=5.0.0",
"list": "readme"
}

View File

@ -0,0 +1,5 @@
title: $:/plugins/tiddlywiki/webdav/readme
This plugin runs in the browser to synchronise tiddler changes to and from a WebDAV-compatible server. It 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.
[[Source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/webdav]]

View File

@ -0,0 +1,6 @@
title: $:/plugins/tiddlywiki/webdav/save/offline
\define saveTiddlerFilter()
[is[tiddler]] -[[$:/boot/boot.css]] -[[$:/HistoryList]] -[type[application/javascript]library[yes]] -[[$:/boot/boot.js]] -[[$:/boot/bootprefix.js]] -[[$:/plugins/tiddlywiki/webdav]] +[sort[title]] $(publishFilter)$
\end
{{$:/core/templates/tiddlywiki5.html}}

View File

@ -0,0 +1,248 @@
/*\
title: $:/plugins/tiddlywiki/webdav/webdavadaptor.js
type: application/javascript
module-type: syncadaptor
A sync adaptor module for synchronising with WebDAV compatible servers
Heavily based on WebDAV Adaptor
Revised by Sebastian Silva <sebastian@fuentelibre.org>
\*/
(function(){
/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";
var CONFIG_HOST_TIDDLER = "$:/config/webdav/host",
DEFAULT_HOST_TIDDLER = "$protocol$//$host$/";
function dirname(path) {
return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, '');
}
function WebDAVAdaptor(options) {
this.wiki = options.wiki;
this.host = this.getHost();
this.tiddlersBaseURL = dirname(location.pathname) + "/tiddlers";
this.hasStatus = false;
this.logger = new $tw.utils.Logger("WebDAVAdaptor");
}
WebDAVAdaptor.prototype.name = "webdav";
WebDAVAdaptor.prototype.knownDirs = [];
WebDAVAdaptor.prototype.isReady = function() {
return this.hasStatus;
};
WebDAVAdaptor.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}
];
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;
};
/*
Make a directory recursively
*/
WebDAVAdaptor.prototype.mkdir_p = function (path, callback) {
var parent = dirname(path);
var self = this;
if (this!==undefined) {
if (!(this.knownDirs.includes(parent))) {
if (parent!==path) {
this.mkdir_p(parent, callback);
}
}
$tw.utils.httpRequest({
type: "MKCOL",
url: this.tiddlersBaseURL + "/" + path,
returnProp: "responseXML",
headers: {accept: "text/xml; charset=UTF-8"},
callback: function(err, doc, request) {
// Check for errors
if(err) {
return callback(err);
}
self.knownDirs.push ( path );
}
});
};
}
WebDAVAdaptor.prototype.getTiddlerInfo = function(tiddler) {
return { };
};
/*
Get the current status of the WebDAV connection
*/
WebDAVAdaptor.prototype.getStatus = function(callback) {
// Get status
var self = this;
this.logger.log("Status is fine");
self.hasStatus = true;
var isLoggedIn = false;
callback(null,isLoggedIn,"GUEST");
// or return callback(err);
};
/*
Get an array of skinny tiddler fields from the server
*/
WebDAVAdaptor.prototype.getSkinnyTiddlers = function(callback) {
var self = this;
$tw.utils.httpRequest({
type: "PROPFIND",
url: this.tiddlersBaseURL + "/",
returnProp: "responseXML",
headers: {accept: "text/xml; charset=UTF-8"},
callback: function(err, doc, request) {
// Check for errors
if(err) {
if (err.indexOf("404")>0) {
$tw.utils.httpRequest({
type: "MKCOL",
url: self.tiddlersBaseURL,
headers: {accept: "text/xml; charset=UTF-8"},
callback: function(err, doc, request) {
// Check for errors
if(err) {
return callback(err);
}
}
});
}
else {
return callback(err);
}
}
if (doc!==undefined) {
const ns = "DAV:";
var tiddlers = [];
var items = doc.children[0].children;
// Start at 1, because the 0th is the same as self.
for(var i=1; i< items.length; i++) {
var response = items[i];
var href = response.getElementsByTagNameNS(ns, 'href')[0].firstChild.nodeValue;
href = href.replace(/\/$/, ''); // Strip trailing slash
href = href.replace(self.tiddlersBaseURL + "/", ""); // Strip path
href = decodeURIComponent(href);
var propstat = response.getElementsByTagNameNS(ns, 'propstat')[0];
var prop = propstat.getElementsByTagNameNS(ns, 'prop')[0];
var resourcetype = prop.getElementsByTagNameNS(ns, 'resourcetype')[0];
var collection = resourcetype.getElementsByTagNameNS(ns, 'collection')[0];
if (prop.getElementsByTagNameNS(ns, 'getcontenttype').length > 0) {
// var type = prop.getElementsByTagNameNS(ns, 'getcontenttype')[0].innerHTML;
if (href.endsWith(".tid") && href!=="$__StoryList.tid") {
var type = "application/x-tiddler";
// var revision = prop.getElementsByTagNameNS(ns, 'getetag')[0].innerHTML;
var revision = prop.getElementsByTagNameNS(ns, 'getlastmodified')[0].innerHTML;
href = href.slice(0, -4);
tiddlers.push({ title: href,
revision: revision,
type: type });
}
}
if (collection) {
if (!(self.knownDirs.includes(href))) {
self.knownDirs.push(href);
}
}
}
callback(null, tiddlers);
}
}
});
};
/*
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
*/
WebDAVAdaptor.prototype.saveTiddler = function(tiddler,callback) {
var self = this;
// Save the tiddler as a self contained templated file
var content = self.wiki.renderTiddler("text/plain","$:/core/templates/tid-tiddler",
{variables: {currentTiddler: tiddler.fields.title}});
var url = this.tiddlersBaseURL + "/" + encodeURIComponent(tiddler.fields.title) + ".tid";
var path = dirname(tiddler.fields.title);
if (path!==tiddler.fields.title && !(self.knownDirs.includes(path))) {
this.mkdir_p(path, callback);
}
$tw.utils.httpRequest({
url: this.tiddlersBaseURL + "/" + tiddler.fields.title + ".tid",
type: "PUT",
headers: {
"Content-type": "text/plain"
},
data: content,
callback: function(err,data,request) {
if(err) {
return callback(err);
}
// Save the details of the new revision of the tiddler
var revision = new Date().toGMTString(); // request.getResponseHeader("Etag");
// Invoke the callback
callback(null, {}, revision);
}
});
};
/*
Load a tiddler and invoke the callback with (err,tiddlerFields)
*/
WebDAVAdaptor.prototype.loadTiddler = function(title,callback) {
var self = this;
$tw.utils.httpRequest({
url: this.tiddlersBaseURL + "/" + title + ".tid",
headers: {accept: "charset=UTF-8"},
callback: function(err,data,request) {
if(err) {
return callback(err);
}
// Invoke the callback
var type = "application/x-tiddler";
var tiddler = $tw.wiki.deserializeTiddlers(type, data)[0];
tiddler.revision = request.getResponseHeader("Last-Modified")
callback(null, tiddler);
}
});
};
/*
Delete a tiddler and invoke the callback with (err)
options include:
tiddlerInfo: the syncer's tiddlerInfo for this tiddler
*/
WebDAVAdaptor.prototype.deleteTiddler = function(title,callback,options) {
// Issue HTTP request to delete the tiddler
$tw.utils.httpRequest({
url: this.tiddlersBaseURL + "/" + title + ".tid",
type: "DELETE",
callback: function(err,data,request) {
if(err) {
return callback(err);
}
// Invoke the callback
callback(null);
}
});
};
if($tw.browser && document.location.protocol.substr(0,4) === "http" ) {
exports.adaptorClass = WebDAVAdaptor;
}
})();