diff --git a/core/modules/savers/download.js b/core/modules/savers/download.js new file mode 100644 index 000000000..207f3a674 --- /dev/null +++ b/core/modules/savers/download.js @@ -0,0 +1,46 @@ +/*\ +title: $:/core/modules/savers/download.js +type: application/javascript +module-type: saver + +Handles saving changes via HTML5's download APIs + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +/* +Select the appropriate saver module and set it up +*/ +var DownloadSaver = function() { +}; + +DownloadSaver.prototype.save = function() { +}; + +/* +Information about this saver +*/ +DownloadSaver.prototype.info = { + name: "download", + priority: 0 +}; + +/* +Static method that returns true if this saver is capable of working +*/ +exports.canSave = function() { + return true; +}; + +/* +Create an instance of this saver +*/ +exports.create = function() { + return new DownloadSaver(); +}; + +})(); diff --git a/core/modules/savers/firefox.js b/core/modules/savers/firefox.js new file mode 100644 index 000000000..5c6e8c7e9 --- /dev/null +++ b/core/modules/savers/firefox.js @@ -0,0 +1,67 @@ +/*\ +title: $:/core/modules/savers/firefox.js +type: application/javascript +module-type: saver + +Handles saving changes via Firefox's XUL APIs + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var FirefoxSaver = function() { +}; + +FirefoxSaver.prototype.save = function(text) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + // Generate the local file path from the file URI + var url = document.location.toString(), + ioService = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService), + fileHandler = ioService.getProtocolHandler("file").QueryInterface(Components.interfaces.nsIFileProtocolHandler), + fileSpec = fileHandler.getFileFromURLSpec(url); +console.log("Saving to",fileSpec.path); + // Try to save the file + var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + file.initWithPath(fileSpec.path); + if(!file.exists()) { + file.create(0,0x01B4);// 0x01B4 = 0664 + } + var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); + out.init(file,0x22,0x04,null); + var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"].createInstance(Components.interfaces.nsIConverterOutputStream); + converter.init(out, "UTF-8", 0, 0); + converter.writeString(text); + converter.close(); + return true; + } catch(ex) { + return false; + } +}; + +/* +Information about this saver +*/ +FirefoxSaver.prototype.info = { + name: "firefox", + priority: 1000 +}; + +/* +Static method that returns true if this saver is capable of working +*/ +exports.canSave = function() { + return !!window.Components; +}; + +/* +Create an instance of this saver +*/ +exports.create = function() { + return new FirefoxSaver(); +}; + +})(); diff --git a/core/modules/startup.js b/core/modules/startup.js index ade8c9f97..3c2ed1eea 100644 --- a/core/modules/startup.js +++ b/core/modules/startup.js @@ -63,6 +63,14 @@ exports.startup = function() { }); // Install the scroller $tw.scroller = new $tw.utils.Scroller(); + // Install the save action handler + $tw.wiki.initSavers(); + document.addEventListener("tw-save-wiki",function(event) { + $tw.wiki.saveWiki({ + template: "$:/core/templates/tiddlywiki5.template.html", + downloadType: "text/plain" + }); + },false); // Get the default tiddlers var defaultTiddlersTitle = "$:/DefaultTiddlers", defaultTiddlersTiddler = $tw.wiki.getTiddler(defaultTiddlersTitle), diff --git a/core/modules/wiki.js b/core/modules/wiki.js index f4364e0ab..76fde42f7 100644 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -478,4 +478,57 @@ exports.initStoryViews = function(moduleType) { } }; +/* +Select the appropriate saver modules and set them up +*/ +exports.initSavers = function(moduleType) { + moduleType = moduleType || "saver"; + // Instantiate the available savers + this.savers = []; + for(var t=0; t<$tw.plugins.moduleTypes[moduleType].length; t++) { + var saver = $tw.plugins.moduleTypes[moduleType][t]; + if(saver.canSave()) { + this.savers.push(saver.create()); + } + } + // 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; + } + } + }); +}; + +/* +Invoke the highest priority saver that successfully handles a method +*/ +exports.callSaver = function(method /*, args */ ) { + for(var t=this.savers.length-1; t>=0; t--) { + var saver = this.savers[t]; + if(saver[method].apply(saver,Array.prototype.slice.call(arguments,1))) { + return true; + } + } + return false; +}; + +/* +Save the wiki contents + template: the tiddler containing the template to save + downloadType: the content type for the saved file +*/ +exports.saveWiki = function(options) { + options = options || {}; + var template = options.template || "$:/core/templates/tiddlywiki5.template.html", + downloadType = options.downloadType || "text/plain", + text = this.renderTiddler(downloadType,template); + this.callSaver("save",text); +}; + })(); diff --git a/core/templates/PageTemplate.tid b/core/templates/PageTemplate.tid index 3bfbf0e54..6d7c94c13 100644 --- a/core/templates/PageTemplate.tid +++ b/core/templates/PageTemplate.tid @@ -22,6 +22,9 @@ title: $:/templates/PageTemplate <