mirror of
				https://github.com/Jermolene/TiddlyWiki5
				synced 2025-11-04 09:33:00 +00:00 
			
		
		
		
	Savetrails: Download before and after files for destructive modifications
This commit is contained in:
		@@ -1,3 +0,0 @@
 | 
			
		||||
title: $:/config/SaveTrailPlugin/save-filter
 | 
			
		||||
 | 
			
		||||
[is[tiddler]] -[[$:/HistoryList]] -[[$:/StoryList]] -[prefix[$:/config/]] -[prefix[$:/temp/]] -[prefix[$:/state/]] -[prefix[$:/status/]]
 | 
			
		||||
@@ -0,0 +1,3 @@
 | 
			
		||||
title: $:/config/SaveTrailPlugin/sync-drafts-filter
 | 
			
		||||
 | 
			
		||||
[is[tiddler]has[draft.of]]
 | 
			
		||||
@@ -1,13 +1,20 @@
 | 
			
		||||
title: $:/plugins/tiddlywiki/savetrail/readme
 | 
			
		||||
 | 
			
		||||
This plugin causes TiddlyWiki to continuously save the contents of each tiddler that is changed as a JSON file. Configured correctly, the browser will download the files silently in the background, and they can be used as a backup in case of accidental data loss.
 | 
			
		||||
This plugin causes TiddlyWiki to continuously download (as a JSON file) the contents of each tiddler that is changed through any means:
 | 
			
		||||
 | 
			
		||||
* Confirming an edit
 | 
			
		||||
* Deleting tiddlers
 | 
			
		||||
* Imports
 | 
			
		||||
* Renames/relinks
 | 
			
		||||
 | 
			
		||||
Where appropriate, separate 'before' and 'after' files are downloaded. Configured correctly, the browser will download the files silently in the background, and they can be used as a backup in case of accidental data loss.
 | 
			
		||||
 | 
			
		||||
''CAUTION'': Using this plugin will generate a //lot// of files in your downloads folder! Some points to watch:
 | 
			
		||||
 | 
			
		||||
* This plugin is pretty much unusable unless your browser is set up to download files automatically, without prompting for the location
 | 
			
		||||
* Automatic file downloading doesn't work in all browsers - in particular, Safari and Internet Explorer do not currently support the [[necessary HTML5 feature|http://caniuse.com/download]]
 | 
			
		||||
* Be aware of the privacy implications of leaving a plaintext trail of all of your edits. You should only enable this plugin on computers that your trust and with content that is not sensitive
 | 
			
		||||
* The plugin uses the tiddler title plus a timestamp to generate a filename for the downloaded file, but some browsers don't respect
 | 
			
		||||
* The plugin uses the tiddler title plus a timestamp to generate a filename for the downloaded file, but some browsers ignore the specified title and generate their own title for each downloaded file
 | 
			
		||||
 | 
			
		||||
Other points to note:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,19 +19,55 @@ exports.after = ["startup"];
 | 
			
		||||
exports.synchronous = true;
 | 
			
		||||
 | 
			
		||||
// Favicon tiddler
 | 
			
		||||
var SAVE_FILTER_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/save-filter",
 | 
			
		||||
	ENABLE_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/enable",
 | 
			
		||||
	ENABLE_DRAFTS_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/enable-drafts";
 | 
			
		||||
var ENABLE_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/enable",
 | 
			
		||||
	ENABLE_DRAFTS_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/enable-drafts",
 | 
			
		||||
	SYNC_DRAFTS_FILTER_TIDDLER_TITLE = "$:/config/SaveTrailPlugin/sync-drafts-filter";
 | 
			
		||||
 | 
			
		||||
exports.startup = function() {
 | 
			
		||||
	$tw.savetrail = $tw.savetrail || {};
 | 
			
		||||
	// Create a syncer to handle autosaving
 | 
			
		||||
	$tw.savetrail.syncadaptor = new SaveTrailSyncAdaptor();
 | 
			
		||||
	$tw.savetrail.syncer = new $tw.Syncer({
 | 
			
		||||
		wiki: $tw.wiki,
 | 
			
		||||
		syncadaptor: $tw.savetrail.syncadaptor,
 | 
			
		||||
		titleSyncFilter: SAVE_FILTER_TIDDLER_TITLE,
 | 
			
		||||
		titleSyncFilter: SYNC_DRAFTS_FILTER_TIDDLER_TITLE,
 | 
			
		||||
		logging: false
 | 
			
		||||
	});
 | 
			
		||||
	// Add hooks for trapping user actions
 | 
			
		||||
	$tw.hooks.addHook("th-saving-tiddler",function(tiddler) {
 | 
			
		||||
		var oldTiddler = $tw.wiki.getTiddler(tiddler.fields.title);
 | 
			
		||||
		if(oldTiddler) {
 | 
			
		||||
			saveTiddlerFile(oldTiddler,{reason: "overwritten"});			
 | 
			
		||||
		}
 | 
			
		||||
		saveTiddlerFile(tiddler,{reason: "saved"});
 | 
			
		||||
		return tiddler;
 | 
			
		||||
	});
 | 
			
		||||
	$tw.hooks.addHook("th-renaming-tiddler",function(newTiddler,oldTiddler) {
 | 
			
		||||
		if(oldTiddler) {
 | 
			
		||||
			saveTiddlerFile(oldTiddler,{reason: "deleted"});			
 | 
			
		||||
		}
 | 
			
		||||
		saveTiddlerFile(newTiddler,{reason: "renamed"});
 | 
			
		||||
		return newTiddler;
 | 
			
		||||
	});
 | 
			
		||||
	$tw.hooks.addHook("th-relinking-tiddler",function(newTiddler,oldTiddler) {
 | 
			
		||||
		if(oldTiddler) {
 | 
			
		||||
			saveTiddlerFile(oldTiddler,{reason: "overwritten"});			
 | 
			
		||||
		}
 | 
			
		||||
		saveTiddlerFile(newTiddler,{reason: "relinked"});
 | 
			
		||||
		return newTiddler;
 | 
			
		||||
	});
 | 
			
		||||
	$tw.hooks.addHook("th-importing-tiddler",function(tiddler) {
 | 
			
		||||
		var oldTiddler = $tw.wiki.getTiddler(tiddler.fields.title);
 | 
			
		||||
		if(oldTiddler) {
 | 
			
		||||
			saveTiddlerFile(oldTiddler,{reason: "overwritten"});			
 | 
			
		||||
		}
 | 
			
		||||
		saveTiddlerFile(tiddler,{reason: "imported"});
 | 
			
		||||
		return tiddler;
 | 
			
		||||
	});
 | 
			
		||||
	$tw.hooks.addHook("th-deleting-tiddler",function(tiddler) {
 | 
			
		||||
		saveTiddlerFile(tiddler,{reason: "deleted"});
 | 
			
		||||
		return tiddler;
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function SaveTrailSyncAdaptor(options) {
 | 
			
		||||
@@ -53,10 +89,10 @@ SaveTrailSyncAdaptor.prototype.getTiddlerInfo = function(tiddler) {
 | 
			
		||||
Save a tiddler and invoke the callback with (err,adaptorInfo,revision)
 | 
			
		||||
*/
 | 
			
		||||
SaveTrailSyncAdaptor.prototype.saveTiddler = function(tiddler,callback) {
 | 
			
		||||
	if($tw.wiki.getTiddlerText(ENABLE_TIDDLER_TITLE).toLowerCase() === "yes") {
 | 
			
		||||
	if($tw.wiki.checkTiddlerText(ENABLE_TIDDLER_TITLE,"yes")) {
 | 
			
		||||
		var isDraft = $tw.utils.hop(tiddler.fields,"draft.of");
 | 
			
		||||
		if(!isDraft || $tw.wiki.getTiddlerText(ENABLE_DRAFTS_TIDDLER_TITLE).toLowerCase() === "yes") {
 | 
			
		||||
			saveTiddlerFile(tiddler);
 | 
			
		||||
		if(!isDraft || $tw.wiki.checkTiddlerText(ENABLE_DRAFTS_TIDDLER_TITLE,"yes")) {
 | 
			
		||||
			saveTiddlerFile(tiddler,{reason: "modified"});
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	callback(null);
 | 
			
		||||
@@ -64,8 +100,6 @@ SaveTrailSyncAdaptor.prototype.saveTiddler = function(tiddler,callback) {
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Load a tiddler and invoke the callback with (err,tiddlerFields)
 | 
			
		||||
 | 
			
		||||
We don't need to implement loading for the file system adaptor, because all the tiddler files will have been loaded during the boot process.
 | 
			
		||||
*/
 | 
			
		||||
SaveTrailSyncAdaptor.prototype.loadTiddler = function(title,callback) {
 | 
			
		||||
	callback(null,null);
 | 
			
		||||
@@ -78,11 +112,13 @@ SaveTrailSyncAdaptor.prototype.deleteTiddler = function(title,callback,options)
 | 
			
		||||
	callback(null);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function saveTiddlerFile(tiddler) {
 | 
			
		||||
	var illegalFilenameCharacters = /<|>|\:|\"|\/|\\|\||\?|\*|\^|\s/g,
 | 
			
		||||
function saveTiddlerFile(tiddler,options) {
 | 
			
		||||
	options = options || {};
 | 
			
		||||
	var reason = options.reason || "changed",
 | 
			
		||||
		illegalFilenameCharacters = /<|>|\:|\"|\/|\\|\||\?|\*|\^|\s/g,
 | 
			
		||||
		fixedTitle = tiddler.fields.title.replace(illegalFilenameCharacters,"_"),
 | 
			
		||||
		formattedDate = $tw.utils.stringifyDate(new Date()),
 | 
			
		||||
		filename =  fixedTitle + "." + formattedDate + ".json",
 | 
			
		||||
		filename =  fixedTitle + "." + formattedDate + "." + reason + ".json",
 | 
			
		||||
		fields = new Object();
 | 
			
		||||
	for(var field in tiddler.fields) {
 | 
			
		||||
		fields[field] = tiddler.getFieldString(field);
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,3 @@ title: $:/plugins/tiddlywiki/savetrail/settings
 | 
			
		||||
<$checkbox tiddler="$:/config/SaveTrailPlugin/enable" field="text" checked="yes" unchecked="no"> Enable automatic saving of modified tiddlers</$checkbox>
 | 
			
		||||
 | 
			
		||||
<$checkbox tiddler="$:/config/SaveTrailPlugin/enable-drafts" field="text" checked="yes" unchecked="no"> Include automatic saving of draft tiddlers (warning: generates a lot of download files)</$checkbox>
 | 
			
		||||
 | 
			
		||||
[[Filter|$:/config/SaveTrailPlugin/save-filter]] used to determine tiddlers that should be autosaved:
 | 
			
		||||
 | 
			
		||||
<$edit-text tiddler="$:/config/SaveTrailPlugin/save-filter" tag="textarea" class="tc-edit-texteditor"/> 
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user