Skip to content
This repository was archived by the owner on Jul 16, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 4 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,10 @@

TiddlyFox is an extension for Mozilla Firefox that enables TiddlyWiki to save changes directly to the file system. TiddlyWiki is complete wiki packaged as a standalone HTML file; see http://tiddlywiki.com/ for more details.

# Installation

TiddlyFox can be installed from Mozilla's Add-ons page:

https://addons.mozilla.org/en-US/firefox/addon/tiddlyfox/

However, due to the duration of Mozilla's approval process, you will often find a more up to date version here on Github:

https://github.com/TiddlyWiki/TiddlyFox/raw/master/tiddlyfox.xpi
This personalised version keeps a one a day backup in the subfolder 'backup' relative to the tiddlywiki.

# Building the extension

The shell script `build_mac.sh` builds `tiddlyfox.api` successfully on Mac OS X.

# Development mode installation

To make it easier to work on the extension, you can configure Firefox to use the unpacked, development version of the extension. To set it up, edit the file `tiddlyfox@tiddlywiki.org` to contain your local path to the TiddlyFox folder, and then drop the file in your `[firefox profile folder]\extensions\` folder.
# Installation
Open the addons page in firefox and select the 'Extensions' tab. Drag and drop the link below into the list of addons.

# Credits
https://github.com/buggyj/TiddlyFox/raw/saver/tiddlyfox.xpi

This extension started life as the sample code accompanying this MozillaZine Knowledge Base article: http://kb.mozillazine.org/Getting_started_with_extension_development
3 changes: 2 additions & 1 deletion content/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The JavaScript in this file is injected into each TiddlyWiki page that loads
var message = document.createElement("div");
message.setAttribute("data-tiddlyfox-path",path);
message.setAttribute("data-tiddlyfox-content",content);
message.setAttribute("data-tiddlyfox-tw2","true");
messageBox.appendChild(message);
// Create and dispatch the custom event to the extension
var event = document.createEvent("Events");
Expand Down Expand Up @@ -52,4 +53,4 @@ The JavaScript in this file is injected into each TiddlyWiki page that loads
window.convertUriToUTF8 = injectedConvertUriToUTF8;
window.convertUnicodeToFileFormat = injectedConvertUnicodeToFileFormat;

})();
})();
240 changes: 236 additions & 4 deletions content/overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,186 @@ The JavaScript code in this file is executed via `overlay.xul` when Firefox star

*/
var TiddlyFox = (function () {
/*
* note that Date is not a 'real' object so you cannot extend it
* so instead we wrap it
*/
var util = {

Date : function () {
this.date = new Date();
},

CreateAPI : function (name, index, array) {
util.Date.prototype[name] =function () {
return(this.date[name]());
}
}
};
["getDate", "getFullYear", "getMonth", "getDay", "getHours", "getMinutes", "getSeconds", "getMilliseconds" ].forEach(util.CreateAPI);
["getUTCDate","getUTCFullYear","getUTCMonth","getUTCDay","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds"].forEach(util.CreateAPI);
["getTime","getTimezoneOffset"].forEach(util.CreateAPI);

// ---------------------------------------------------------------------------------
// Start of Utility functions copied from TiddlyWiki.
// ---------------------------------------------------------------------------------

var zeroPad = function(n,d)
{
var s = n.toString();
if(s.length < d)
s = "000000000000000000000000000".substr(0,d-s.length) + s;
return(s);
}

// Convert a date to UTC YYYYMMDDHHMM string format
util.Date.prototype.convertToYYYYMMDDHHMM = function()
{
return(zeroPad(this.getUTCFullYear(),4) + zeroPad(this.getUTCMonth()+1,2) + zeroPad(this.getUTCDate(),2) + zeroPad(this.getUTCHours(),2) + zeroPad(this.getUTCMinutes(),2));
}

// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
util.Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
{
return(zeroPad(this.getUTCFullYear(),4) + zeroPad(this.getUTCMonth()+1,2) + zeroPad(this.getUTCDate(),2) + "." + zeroPad(this.getUTCHours(),2) + zeroPad(this.getUTCMinutes(),2) + zeroPad(this.getUTCSeconds(),2) + zeroPad(this.getUTCMilliseconds(),4));
}

// Convert a date to UTC YYYY-MM-DD HH:MM string format
util.Date.prototype.convertToFullDate = function()
{
return(zeroPad(this.getUTCFullYear(),4) + "-" +
zeroPad(this.getUTCMonth()+1,2) + "-" +
zeroPad(this.getUTCDate(),2) + " " +
zeroPad(this.getUTCHours(),2) + ":" +
zeroPad(this.getUTCMinutes(),2));
}

util.Date.prototype.formatString = function(template)
{
var t = template.replace(/0hh12/g,zeroPad(this.getHours12(),2));
t = t.replace(/hh12/g,this.getHours12());
t = t.replace(/0hh/g,zeroPad(this.getHours(),2));
t = t.replace(/hh/g,this.getHours());
t = t.replace(/mmm/g,dateS.shortMonths[this.getMonth()]);
t = t.replace(/0mm/g,zeroPad(this.getMinutes(),2));
t = t.replace(/mm/g,this.getMinutes());
t = t.replace(/0ss/g,zeroPad(this.getSeconds(),2));
t = t.replace(/ss/g,this.getSeconds());
t = t.replace(/[ap]m/g,this.getAmPm().toLowerCase());
t = t.replace(/[AP]M/g,this.getAmPm().toUpperCase());
t = t.replace(/wYYYY/g,this.getYearForWeekNo());
t = t.replace(/wYY/g,zeroPad(this.getYearForWeekNo()-2000,2));
t = t.replace(/YYYY/g,this.getFullYear());
t = t.replace(/YY/g,zeroPad(this.getFullYear()-2000,2));
t = t.replace(/MMM/g,dateS.months[this.getMonth()]);
t = t.replace(/0MM/g,zeroPad(this.getMonth()+1,2));
t = t.replace(/MM/g,this.getMonth()+1);
t = t.replace(/0WW/g,zeroPad(this.getWeek(),2));
t = t.replace(/WW/g,this.getWeek());
t = t.replace(/DDD/g,dateS.days[this.getDay()]);
t = t.replace(/ddd/g,dateS.shortDays[this.getDay()]);
t = t.replace(/0DD/g,zeroPad(this.getDate(),2));
t = t.replace(/DDth/g,this.getDate()+this.daySuffix());
t = t.replace(/DD/g,this.getDate());
var tz = this.getTimezoneOffset();
var atz = Math.abs(tz);
t = t.replace(/TZD/g,(tz < 0 ? '+' : '-') + zeroPad(Math.floor(atz / 60),2) + ':' + zeroPad(atz % 60,2));
t = t.replace(/\\/g,"");
return t;
};

util.Date.prototype.getWeek = function()
{
var dt = new Date(this.getTime());
var d = dt.getDay();
if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week to calculate weekNo
var n = Math.floor((dt.getTime()-new Date(dt.getFullYear(),0,1)+3600000)/86400000);
return Math.floor(n/7)+1;
};

util.Date.prototype.getYearForWeekNo = function()
{
var dt = new Date(this.getTime());
var d = dt.getDay();
if(d==0) d=7;// JavaScript Sun=0, ISO Sun=7
dt.setTime(dt.getTime()+(4-d)*86400000);// shift day to Thurs of same week
return dt.getFullYear();
};

util.Date.prototype.getHours12 = function()
{
var h = this.getHours();
return h > 12 ? h-12 : ( h > 0 ? h : 12 );
};

util.Date.prototype.getAmPm = function()
{
return this.getHours() >= 12 ? dateS.pm : dateS.am;
};

util.Date.prototype.daySuffix = function()
{
return dateS.daySuffixes[this.getDate()-1];
};

// Convert a date to local YYYYMMDDHHMM string format
util.Date.prototype.convertToLocalYYYYMMDDHHMM = function()
{
return this.getFullYear() + zeroPad(this.getMonth()+1,2) + zeroPad(this.getDate(),2) + zeroPad(this.getHours(),2) + zeroPad(this.getMinutes(),2);
};

// Convert a date to UTC YYYYMMDDHHMM string format
util.Date.prototype.convertToYYYYMMDDHHMM = function()
{
return this.getUTCFullYear() + zeroPad(this.getUTCMonth()+1,2) + zeroPad(this.getUTCDate(),2) + zeroPad(this.getUTCHours(),2) + zeroPad(this.getUTCMinutes(),2);
};

// Convert a date to UTC YYYYMMDD.HHMMSSMMM string format
util.Date.prototype.convertToYYYYMMDDHHMMSSMMM = function()
{
return this.getUTCFullYear() + zeroPad(this.getUTCMonth()+1,2) + zeroPad(this.getUTCDate(),2) + "." + zeroPad(this.getUTCHours(),2) + zeroPad(this.getUTCMinutes(),2) + zeroPad(this.getUTCSeconds(),2) + zeroPad(this.getUTCMilliseconds(),3) +"0";
};

// Static method to create a date from a UTC YYYYMMDDHHMM format string
util.Date.convertFromYYYYMMDDHHMM = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return util.Date.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,12));
};

// Static method to create a date from a UTC YYYYMMDDHHMMSS format string
util.Date.convertFromYYYYMMDDHHMMSS = function(d)
{
d = d?d.replace(/[^0-9]/g, ""):"";
return util.Date.convertFromYYYYMMDDHHMMSSMMM(d.substr(0,14));
};

// Static method to create a date from a UTC YYYYMMDDHHMMSSMMM format string
util.Date.convertFromYYYYMMDDHHMMSSMMM = function(d)
{
d = d ? d.replace(/[^0-9]/g, "") : "";
return new Date(Date.UTC(parseInt(d.substr(0,4),10),
parseInt(d.substr(4,2),10)-1,
parseInt(d.substr(6,2),10),
parseInt(d.substr(8,2)||"00",10),
parseInt(d.substr(10,2)||"00",10),
parseInt(d.substr(12,2)||"00",10),
parseInt(d.substr(14,3)||"000",10)));
};
var dateS ={};
dateS.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November","December"];
dateS.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
dateS.shortMonths = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
dateS.shortDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
// suffixes for dates, eg "1st","2nd","3rd"..."30th","31st"
dateS.daySuffixes = ["st","nd","rd","th","th","th","th","th","th","th",
"th","th","th","th","th","th","th","th","th","th",
"st","nd","rd","th","th","th","th","th","th","th",
"st"];
dateS.am = "am";
dateS.pm = "pm";

var TiddlyFox = {

// Name of the permission for TiddlyFox used by Firefox
Expand Down Expand Up @@ -80,8 +260,23 @@ var TiddlyFox = {
// Attach the event handler to the message box
messageBox.addEventListener("tiddlyfox-save-file",TiddlyFox.onSaveFile,false);
},
moveFile: function(sourcefile,destdir,onceaday) {
var aFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
if (!aFile) return false;

var aDir = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
if (!aDir) return false;

aFile.initWithPath(sourcefile);
aDir.initWithPath(TiddlyFox.getBackupPath(sourcefile,destdir));

saveFile: function(filePath,content) {

aFile.moveTo(aDir,TiddlyFox.getBackupFile(sourcefile,onceaday));
},

saveFile: function(filePath,content,destdir,onceaday) {
// Attempt to convert the filepath to a proper UTF-8 string
try {
var converter = Components.classes["@mozilla.org/intl/utf8converterservice;1"].getService(Components.interfaces.nsIUTF8ConverterService);
Expand All @@ -90,8 +285,11 @@ var TiddlyFox = {
}
// Save the file
try {
if (destdir)
TiddlyFox.moveFile(filePath,destdir,onceaday);
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filePath);

if(!file.exists())
file.create(0,0x01B4);// 0x01B4 = 0664
var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
Expand All @@ -108,14 +306,47 @@ var TiddlyFox = {
}
},

getBackupPath: function(localPath,destdir) {
var slash = "\\";
var dirPathPos = localPath.lastIndexOf("\\");
if(dirPathPos == -1) {
dirPathPos = localPath.lastIndexOf("/");
slash = "/";
}
var backupFolder = destdir;//config.options.txtBackupFolder;
if(!backupFolder || backupFolder == "")
backupFolder = ".";
backupFolder=localPath.substr(0,dirPathPos) + slash + backupFolder;
return backupFolder;
},
getBackupFile: function(localPath,onceaday) {
var slash = "\\";
var dirPathPos = localPath.lastIndexOf("\\");
if(dirPathPos == -1) {
dirPathPos = localPath.lastIndexOf("/");
slash = "/";
}
var backupPath = localPath.substr(dirPathPos+1);
backupPath = backupPath.substr(0,backupPath.lastIndexOf(".")) + ".";
if (onceaday)
backupPath += (new util.Date()).convertToYYYYMMDDHHMMSSMMM().replace (/(.*)\.(.*)/,"$1") + "." + "html";
else
backupPath += (new util.Date()).convertToYYYYMMDDHHMMSSMMM() + "." + "html";
return backupPath;
},
onSaveFile: function(event) {
// Get the details from the message
var message = event.target,
path = message.getAttribute("data-tiddlyfox-path"),
content = message.getAttribute("data-tiddlyfox-content");
content = message.getAttribute("data-tiddlyfox-content"),
backupdir = message.getAttribute("data-tiddlyfox-backupdir"),
onceaday = message.getAttribute("data-tiddlyfox-onceaday"),
tw2 =message.getAttribute("data-tiddlyfox-tw2");
// Save the file
TiddlyFox.saveFile(path,content);
// Remove the message element from the message box
if (tw2)
TiddlyFox.saveFile(path,content);
else
TiddlyFox.saveFile(path,content,"backup",true);
message.parentNode.removeChild(message);
// Send a confirmation message
var event = document.createEvent("Events");
Expand Down Expand Up @@ -180,4 +411,5 @@ window.addEventListener("load",function load(event) {
TiddlyFox.onLoad(event);
},false);
return TiddlyFox;

}());
Binary file modified tiddlyfox.xpi
Binary file not shown.