mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-12-27 02:20:28 +00:00
13c4e028b1
Previously we were using a message `tw-auto-save-wiki` to trigger an autosave. The message was generated by certain UI actions such as saving a tiddler. The trouble was that the message was being processed before the wiki change event for the accompanying change had had a chance to percolate. The end result was that the dirty indicator was staying lit when using autosave. The new approach abandons the autosave message and instead triggers the autosave in the wiki change event when a relevant change occurs. One happy side effect of these changes is that the dirty indicator now works as expected with the client server edition - ie, when typing in a draft tiddler the dirty indicator will flash briefly, and then clear when the sync mechanism has completed saving the draft.
174 lines
5.7 KiB
JavaScript
174 lines
5.7 KiB
JavaScript
/*\
|
|
title: $:/core/modules/saver-handler.js
|
|
type: application/javascript
|
|
module-type: global
|
|
|
|
The saver handler tracks changes to the store and handles saving the entire wiki via saver modules.
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
/*
|
|
Instantiate the saver handler with the following options:
|
|
wiki: wiki to be synced
|
|
dirtyTracking: true if dirty tracking should be performed
|
|
*/
|
|
function SaverHandler(options) {
|
|
var self = this;
|
|
this.wiki = options.wiki;
|
|
this.dirtyTracking = options.dirtyTracking;
|
|
// Make a logger
|
|
this.logger = new $tw.utils.Logger("saver-handler");
|
|
// Initialise our savers
|
|
if($tw.browser) {
|
|
this.initSavers();
|
|
}
|
|
// Only do dirty tracking if required
|
|
if($tw.browser && this.dirtyTracking) {
|
|
// Compile the dirty tiddler filter
|
|
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
|
// Count of tiddlers that have been changed but not yet saved
|
|
this.numTasksInQueue = 0;
|
|
// Listen out for changes to tiddlers
|
|
this.wiki.addEventListener("change",function(changes) {
|
|
var filteredChanges = self.filterFn.call(self.wiki,function(callback) {
|
|
$tw.utils.each(changes,function(change,title) {
|
|
var tiddler = self.wiki.getTiddler(title);
|
|
callback(tiddler,title);
|
|
});
|
|
});
|
|
self.numTasksInQueue += filteredChanges.length;
|
|
self.updateDirtyStatus();
|
|
if(self.numTasksInQueue > 0) {
|
|
self.saveWiki({method: "autosave"});
|
|
}
|
|
});
|
|
// Browser event handlers
|
|
if($tw.browser) {
|
|
// Set up our beforeunload handler
|
|
window.addEventListener("beforeunload",function(event) {
|
|
var confirmationMessage = undefined;
|
|
if(self.isDirty()) {
|
|
confirmationMessage = $tw.language.getString("UnsavedChangesWarning");
|
|
event.returnValue = confirmationMessage; // Gecko
|
|
}
|
|
return confirmationMessage;
|
|
});
|
|
}
|
|
}
|
|
// Install the save action handlers
|
|
if($tw.browser) {
|
|
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
|
self.saveWiki({
|
|
template: event.param,
|
|
downloadType: "text/plain"
|
|
});
|
|
});
|
|
$tw.rootWidget.addEventListener("tw-download-file",function(event) {
|
|
self.saveWiki({
|
|
method: "download",
|
|
template: event.param,
|
|
downloadType: "text/plain"
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
SaverHandler.prototype.titleSyncFilter = "$:/config/SaverFilter";
|
|
SaverHandler.prototype.titleAutoSave = "$:/config/AutoSave";
|
|
SaverHandler.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
|
|
|
/*
|
|
Select the appropriate saver modules and set them up
|
|
*/
|
|
SaverHandler.prototype.initSavers = function(moduleType) {
|
|
moduleType = moduleType || "saver";
|
|
// Instantiate the available savers
|
|
this.savers = [];
|
|
var self = this;
|
|
$tw.modules.forEachModuleOfType(moduleType,function(title,module) {
|
|
if(module.canSave(self)) {
|
|
self.savers.push(module.create(self.wiki));
|
|
}
|
|
});
|
|
// Sort the savers into priority order
|
|
this.savers.sort(function(a,b) {
|
|
if(a.info.priority < b.info.priority) {
|
|
return -1;
|
|
} else {
|
|
if(a.info.priority > b.info.priority) {
|
|
return +1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
/*
|
|
Save the wiki contents. Options are:
|
|
method: "save", "autosave" or "download"
|
|
template: the tiddler containing the template to save
|
|
downloadType: the content type for the saved file
|
|
*/
|
|
SaverHandler.prototype.saveWiki = function(options) {
|
|
options = options || {};
|
|
var self = this,
|
|
method = options.method || "save",
|
|
template = options.template || "$:/core/save/all",
|
|
downloadType = options.downloadType || "text/plain",
|
|
text = this.wiki.renderTiddler(downloadType,template),
|
|
callback = function(err) {
|
|
if(err) {
|
|
alert("Error while saving:\n\n" + err);
|
|
} else {
|
|
// Clear the task queue if we're saving (rather than downloading)
|
|
if(method !== "download") {
|
|
self.numTasksInQueue = 0;
|
|
self.updateDirtyStatus();
|
|
}
|
|
$tw.notifier.display(self.titleSavedNotification);
|
|
if(options.callback) {
|
|
options.callback();
|
|
}
|
|
}
|
|
};
|
|
// Ignore autosave if disabled
|
|
if(method === "autosave" && this.wiki.getTiddlerText(this.titleAutoSave,"yes") !== "yes") {
|
|
return false;
|
|
}
|
|
// Call the highest priority saver that supports this method
|
|
for(var t=this.savers.length-1; t>=0; t--) {
|
|
var saver = this.savers[t];
|
|
if(saver.info.capabilities.indexOf(method) !== -1 && saver.save(text,method,callback)) {
|
|
this.logger.log("Saving wiki with method",method,"through saver",saver.info.name);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/*
|
|
Checks whether the wiki is dirty (ie the window shouldn't be closed)
|
|
*/
|
|
SaverHandler.prototype.isDirty = function() {
|
|
return this.numTasksInQueue > 0;
|
|
};
|
|
|
|
/*
|
|
Update the document body with the class "tw-dirty" if the wiki has unsaved/unsynced changes
|
|
*/
|
|
SaverHandler.prototype.updateDirtyStatus = function() {
|
|
if($tw.browser) {
|
|
$tw.utils.toggleClass(document.body,"tw-dirty",this.isDirty());
|
|
}
|
|
};
|
|
|
|
exports.SaverHandler = SaverHandler;
|
|
|
|
})();
|