mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-02-20 04:50:03 +00:00
Separate the saver handling out of the syncer
This commit is contained in:
parent
27f1f82a70
commit
f75af2c983
170
core/modules/saver-handler.js
Normal file
170
core/modules/saver-handler.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*\
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
function SaverHandler(options) {
|
||||||
|
var self = this;
|
||||||
|
this.wiki = options.wiki;
|
||||||
|
// Make a logger
|
||||||
|
this.logger = new $tw.utils.Logger("saver-handler");
|
||||||
|
// Initialise our savers
|
||||||
|
if($tw.browser) {
|
||||||
|
this.initSavers();
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
});
|
||||||
|
// 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
|
||||||
|
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
||||||
|
self.saveWiki({
|
||||||
|
template: event.param,
|
||||||
|
downloadType: "text/plain"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$tw.rootWidget.addEventListener("tw-auto-save-wiki",function(event) {
|
||||||
|
self.saveWiki({
|
||||||
|
method: "autosave",
|
||||||
|
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/SyncFilter";
|
||||||
|
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" 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 {
|
||||||
|
$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);
|
||||||
|
// Clear the task queue if we're saving (rather than downloading)
|
||||||
|
if(method !== "download") {
|
||||||
|
this.numTasksInQueue = 0;
|
||||||
|
this.updateDirtyStatus();
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
|
||||||
|
})();
|
@ -69,9 +69,11 @@ exports.startup = function() {
|
|||||||
$tw.syncadaptor = new module.adaptorClass({wiki: $tw.wiki});
|
$tw.syncadaptor = new module.adaptorClass({wiki: $tw.wiki});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Set up the syncer object
|
// Set up the syncer object if we've got a syncadaptor, otherwise setup the saverhandler
|
||||||
if($tw.syncadaptor) {
|
if($tw.syncadaptor) {
|
||||||
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
|
$tw.syncer = new $tw.Syncer({wiki: $tw.wiki, syncadaptor: $tw.syncadaptor});
|
||||||
|
} else {
|
||||||
|
$tw.saverHandler = new $tw.SaverHandler({wiki: $tw.wiki});
|
||||||
}
|
}
|
||||||
// Host-specific startup
|
// Host-specific startup
|
||||||
if($tw.browser) {
|
if($tw.browser) {
|
||||||
|
@ -23,10 +23,6 @@ function Syncer(options) {
|
|||||||
this.syncadaptor = options.syncadaptor
|
this.syncadaptor = options.syncadaptor
|
||||||
// Make a logger
|
// Make a logger
|
||||||
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : ""));
|
this.logger = new $tw.utils.Logger("syncer" + ($tw.browser ? "-browser" : "") + ($tw.node ? "-server" : ""));
|
||||||
// Initialise our savers
|
|
||||||
if($tw.browser) {
|
|
||||||
this.initSavers();
|
|
||||||
}
|
|
||||||
// Compile the dirty tiddler filter
|
// Compile the dirty tiddler filter
|
||||||
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
this.filterFn = this.wiki.compileFilter(this.wiki.getTiddlerText(this.titleSyncFilter));
|
||||||
// Record information for known tiddlers
|
// Record information for known tiddlers
|
||||||
@ -61,34 +57,11 @@ function Syncer(options) {
|
|||||||
$tw.rootWidget.addEventListener("tw-server-refresh",function() {
|
$tw.rootWidget.addEventListener("tw-server-refresh",function() {
|
||||||
self.handleRefreshEvent();
|
self.handleRefreshEvent();
|
||||||
});
|
});
|
||||||
// Install the save action handlers
|
|
||||||
$tw.rootWidget.addEventListener("tw-save-wiki",function(event) {
|
|
||||||
self.saveWiki({
|
|
||||||
template: event.param,
|
|
||||||
downloadType: "text/plain"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$tw.rootWidget.addEventListener("tw-auto-save-wiki",function(event) {
|
|
||||||
self.saveWiki({
|
|
||||||
method: "autosave",
|
|
||||||
template: event.param,
|
|
||||||
downloadType: "text/plain"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
$tw.rootWidget.addEventListener("tw-download-file",function(event) {
|
|
||||||
self.saveWiki({
|
|
||||||
method: "download",
|
|
||||||
template: event.param,
|
|
||||||
downloadType: "text/plain"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// Listen out for lazyLoad events
|
// Listen out for lazyLoad events
|
||||||
if(this.syncadaptor) {
|
this.wiki.addEventListener("lazyLoad",function(title) {
|
||||||
this.wiki.addEventListener("lazyLoad",function(title) {
|
self.handleLazyLoadEvent(title);
|
||||||
self.handleLazyLoadEvent(title);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
// Get the login status
|
// Get the login status
|
||||||
this.getStatus(function (err,isLoggedIn) {
|
this.getStatus(function (err,isLoggedIn) {
|
||||||
// Do a sync from the server
|
// Do a sync from the server
|
||||||
@ -102,7 +75,6 @@ Constants
|
|||||||
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
|
Syncer.prototype.titleIsLoggedIn = "$:/status/IsLoggedIn";
|
||||||
Syncer.prototype.titleUserName = "$:/status/UserName";
|
Syncer.prototype.titleUserName = "$:/status/UserName";
|
||||||
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
Syncer.prototype.titleSyncFilter = "$:/config/SyncFilter";
|
||||||
Syncer.prototype.titleAutoSave = "$:/config/AutoSave";
|
|
||||||
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
Syncer.prototype.titleSavedNotification = "$:/language/Notifications/Save/Done";
|
||||||
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
|
Syncer.prototype.taskTimerInterval = 1 * 1000; // Interval for sync timer
|
||||||
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
|
Syncer.prototype.throttleInterval = 1 * 1000; // Defer saving tiddlers if they've changed in the last 1s...
|
||||||
@ -129,79 +101,6 @@ Syncer.prototype.readTiddlerInfo = function() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
Select the appropriate saver modules and set them up
|
|
||||||
*/
|
|
||||||
Syncer.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" or "download"
|
|
||||||
template: the tiddler containing the template to save
|
|
||||||
downloadType: the content type for the saved file
|
|
||||||
*/
|
|
||||||
Syncer.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 {
|
|
||||||
$tw.notifier.display(self.titleSavedNotification);
|
|
||||||
if(options.callback) {
|
|
||||||
options.callback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Ignore autosave if we've got a syncadaptor or autosave is disabled
|
|
||||||
if(method === "autosave") {
|
|
||||||
if(this.syncadaptor || 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);
|
|
||||||
// Clear the task queue if we're saving (rather than downloading)
|
|
||||||
if(method !== "download") {
|
|
||||||
this.readTiddlerInfo();
|
|
||||||
this.taskQueue = {};
|
|
||||||
this.updateDirtyStatus();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Checks whether the wiki is dirty (ie the window shouldn't be closed)
|
Checks whether the wiki is dirty (ie the window shouldn't be closed)
|
||||||
*/
|
*/
|
||||||
@ -453,9 +352,7 @@ Syncer.prototype.enqueueSyncTask = function(task) {
|
|||||||
this.updateDirtyStatus();
|
this.updateDirtyStatus();
|
||||||
}
|
}
|
||||||
// Process the queue
|
// Process the queue
|
||||||
if(this.syncadaptor) {
|
$tw.utils.nextTick(function() {self.processTaskQueue.call(self);});
|
||||||
$tw.utils.nextTick(function() {self.processTaskQueue.call(self);});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user