Skip to content

Commit

Permalink
Initial working version
Browse files Browse the repository at this point in the history
  • Loading branch information
jgillula committed Jun 23, 2019
1 parent 9ad6ea2 commit cf6845f
Show file tree
Hide file tree
Showing 12 changed files with 1,198 additions and 25 deletions.
516 changes: 492 additions & 24 deletions LICENSE

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Enhanced-Date-Format-for-Thunderbird
Extension for Thunderbird that lets the user configure how dates are displayed.
Extension for Thunderbird that lets the user customize how dates are formatted when they're displayed.

This extension is substantially based on [Super Date Format](https://addons.thunderbird.net/en-US/thunderbird/addon/super-date-format/) by Yonas Yanfa.

(c) 2019 by Jeremy Gillula under the Mozilla Public License, except for the strftime function in [src/chrome/content/namespace.js](src/chrome/content/namespace.js), which is taken from [https://github.com/thdoan/strftime](https://github.com/thdoan/strftime) and is (c) 2016 by Tom Doan, and used here under the MIT Public License.
5 changes: 5 additions & 0 deletions src/chrome.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
content enhanceddateformatter chrome/content/

skin enhanceddateformatter classic/1.0 skins/classic/

overlay chrome://messenger/content/messenger.xul chrome://enhanceddateformatter/content/messenger_overlay.xul
196 changes: 196 additions & 0 deletions src/chrome/content/enhancedDateFormatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/**
* Enhanced Date Formatter namespace.
*/
if (typeof EnhancedDateFormatter == "undefined") {
var EnhancedDateFormatter = {};
};

EnhancedDateFormatter.getDateFormatForDate = function (date) {
var dateFormat = EnhancedDateFormatter.preferences.getValue('defaultDateFormat', '');

// JS dates are stored as milliseconds since midnight on
// January 1, 1970, UTC, and there are 86400000 in a day, so
// to get the number of days, just divide by 86400000 and
// floor the result
var todayDay = Math.floor((new Date()).valueOf()/86400000);
var dateDay = Math.floor(date.valueOf()/86400000);

if (EnhancedDateFormatter.preferences.getValue('useCustomFormatForLastWeek', false) &&
dateDay > (todayDay-7)) {
dateFormat = EnhancedDateFormatter.preferences.getValue('lastWeekDateFormat', '');
}
if (EnhancedDateFormatter.preferences.getValue('useCustomFormatForYesterday', false) &&
dateDay == (todayDay-1)) {
dateFormat = EnhancedDateFormatter.preferences.getValue('yesterdayDateFormat', '');
}
if (EnhancedDateFormatter.preferences.getValue('useCustomFormatForToday', false) &&
dateDay == todayDay) {
dateFormat = EnhancedDateFormatter.preferences.getValue('todayDateFormat', '');
}

return dateFormat;
};


EnhancedDateFormatter.strftime = function(sFormat, date) {

if (!(date instanceof Date)) date = new Date();
var nDay = date.getDay(),
nDate = date.getDate(),
nMonth = date.getMonth(),
nYear = date.getFullYear(),
nHour = date.getHours(),
aDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
aMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
aDayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
isLeapYear = function() {
return (nYear%4===0 && nYear%100!==0) || nYear%400===0;
},
getThursday = function() {
var target = new Date(date);
target.setDate(nDate - ((nDay+6)%7) + 3);
return target;
},
zeroPad = function(nNum, nPad) {
return ((Math.pow(10, nPad) + nNum) + '').slice(1);
};
return sFormat.replace(/%[a-z]/gi, function(sMatch) {
return (({
'%a': aDays[nDay].slice(0,3),
'%A': aDays[nDay],
'%b': aMonths[nMonth].slice(0,3),
'%B': aMonths[nMonth],
'%c': date.toUTCString(),
'%C': Math.floor(nYear/100),
'%d': zeroPad(nDate, 2),
'%e': nDate,
'%F': date.toISOString().slice(0,10),
'%G': getThursday().getFullYear(),
'%g': (getThursday().getFullYear() + '').slice(2),
'%H': zeroPad(nHour, 2),
'%I': zeroPad((nHour+11)%12 + 1, 2),
'%j': zeroPad(aDayCount[nMonth] + nDate + ((nMonth>1 && isLeapYear()) ? 1 : 0), 3),
'%k': nHour,
'%l': (nHour+11)%12 + 1,
'%m': zeroPad(nMonth + 1, 2),
'%n': nMonth + 1,
'%M': zeroPad(date.getMinutes(), 2),
'%p': (nHour<12) ? 'AM' : 'PM',
'%P': (nHour<12) ? 'am' : 'pm',
'%s': Math.round(date.getTime()/1000),
'%S': zeroPad(date.getSeconds(), 2),
'%u': nDay || 7,
'%V': (function() {
var target = getThursday(),
n1stThu = target.valueOf();
target.setMonth(0, 1);
var nJan1 = target.getDay();
if (nJan1!==4) target.setMonth(0, 1 + ((4-nJan1)+7)%7);
return zeroPad(1 + Math.ceil((n1stThu-target)/604800000), 2);
})(),
'%w': nDay,
'%x': date.toLocaleDateString(),
'%X': date.toLocaleTimeString(),
'%y': (nYear + '').slice(2),
'%Y': nYear,
'%z': date.toTimeString().replace(/.+GMT([+-]\d+).+/, '$1'),
'%Z': date.toTimeString().replace(/.+\((.+?)\)$/, '$1')
}[sMatch] || '') + '') || sMatch;
});
};


EnhancedDateFormatter.PreferencesManager = function() {
var startPoint="extensions.enhancedDateFormatter.";

var pref=Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService).
getBranch(startPoint);

var observers={};

// whether a preference exists
this.exists=function(prefName) {
return pref.getPrefType(prefName) != 0;
}

// returns the named preference, or defaultValue if it does not exist
this.getValue=function(prefName, defaultValue) {
var prefType=pref.getPrefType(prefName);

// underlying preferences object throws an exception if pref doesn't exist
if (prefType==pref.PREF_INVALID) {
return defaultValue;
}

switch (prefType) {
case pref.PREF_STRING: return pref.getCharPref(prefName);
case pref.PREF_BOOL: return pref.getBoolPref(prefName);
case pref.PREF_INT: return pref.getIntPref(prefName);
}
}

// sets the named preference to the specified value. values must be strings,
// booleans, or integers.
this.setValue=function(prefName, value) {
var prefType=typeof(value);

switch (prefType) {
case "string":
case "boolean":
break;
case "number":
if (value % 1 != 0) {
throw new Error("Cannot set preference to non integral number");
}
break;
default:
throw new Error("Cannot set preference with datatype: " + prefType);
}

// underlying preferences object throws an exception if new pref has a
// different type than old one. i think we should not do this, so delete
// old pref first if this is the case.
if (this.exists(prefName) && prefType != typeof(this.getValue(prefName))) {
this.remove(prefName);
}

// set new value using correct method
switch (prefType) {
case "string": pref.setCharPref(prefName, value); break;
case "boolean": pref.setBoolPref(prefName, value); break;
case "number": pref.setIntPref(prefName, Math.floor(value)); break;
}
}

// deletes the named preference or subtree
this.remove=function(prefName) {
pref.deleteBranch(prefName);
}

// call a function whenever the named preference subtree changes
this.watch=function(prefName, watcher) {
// construct an observer
var observer={
observe:function(subject, topic, prefName) {
watcher(prefName);
}
};

// store the observer in case we need to remove it later
observers[watcher]=observer;

pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal).
addObserver(prefName, observer, false);
}

// stop watching
this.unwatch=function(prefName, watcher) {
if (observers[watcher]) {
pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal)
.removeObserver(prefName, observers[watcher]);
}
}
}

EnhancedDateFormatter.preferences = new EnhancedDateFormatter.PreferencesManager();
Binary file added src/chrome/content/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions src/chrome/content/messenger_overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
EnhancedDateFormatter.ColumnHandler = function(colName) {
this.colName = colName;
};

EnhancedDateFormatter.ColumnHandler.prototype = {
getCellText: function(row, col) {
//get the message's header so that we can extract the date field
var hdr = gDBView.getMsgHdrAt(row);
var date = new Date(this._fetchDate(hdr));

return EnhancedDateFormatter.strftime(EnhancedDateFormatter.getDateFormatForDate(date), date);
},
_fetchDate: function(hdr) {
if (this.colName == "dateCol") {
return hdr.date / 1000;
} else if (this.colName == "receivedCol") {
return hdr.getUint32Property("dateReceived") * 1000;
} else {
return null;
}
},
getSortStringForRow: function(hdr) {return hdr.date;},
isString: function() {return true;},

getCellProperties: function(row, col, props){},
getRowProperties: function(row, props){},
getImageSrc: function(row, col) {return null;},
getSortLongForRow: function(hdr) {return hdr.date;}
};

EnhancedDateFormatter.CreateDbObserver = {
// Components.interfaces.nsIObserver
observe: function(aMsgFolder, aTopic, aData)
{
if (EnhancedDateFormatter.preferences.getValue('useCustomFormatsForDateColumn', false)) {
gDBView.addColumnHandler("dateCol", new EnhancedDateFormatter.ColumnHandler('dateCol'));
}

if (EnhancedDateFormatter.preferences.getValue('useCustomFormatsForReceivedColumn', false)) {
gDBView.addColumnHandler("receivedCol", new EnhancedDateFormatter.ColumnHandler('receivedCol'));
}
}
};

EnhancedDateFormatter.FormatMessagePaneDate = function() {
var date = new Date(currentHeaderData["date"].headerValue);
currentHeaderData["x-mozilla-localizeddate"].headerValue = EnhancedDateFormatter.strftime(EnhancedDateFormatter.getDateFormatForDate(date), date);
}

EnhancedDateFormatter.doOnceLoaded = function() {
var ObserverService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
ObserverService.addObserver(EnhancedDateFormatter.CreateDbObserver, "MsgCreateDBView", false);
if (EnhancedDateFormatter.preferences.getValue('useCustomFormatsForMessagePane', false)) {
gMessageListeners.push({
onStartHeaders: function () {},
onEndHeaders: function () {},
onEndAttachments: function () {},
onBeforeShowHeaderPane: EnhancedDateFormatter.FormatMessagePaneDate
});
}
};

window.addEventListener("load", EnhancedDateFormatter.doOnceLoaded, false);
8 changes: 8 additions & 0 deletions src/chrome/content/messenger_overlay.xul
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<overlay id="EnhancedDateFormatterColumnsOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<!-- include our javascript files -->
<script type="text/javascript" src="chrome://enhanceddateformatter/content/enhancedDateFormatter.js"/>
<script type="text/javascript" src="chrome://enhanceddateformatter/content/messenger_overlay.js"/>
</overlay>
47 changes: 47 additions & 0 deletions src/chrome/content/preferences.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function setDisabledOrEnabled(ids, value) {
if(value) {
for (let id of ids) {
document.getElementById(id).removeAttribute("disabled");
}
} else {
for (let id of ids) {
document.getElementById(id).setAttribute("disabled", "true");
}
}
}

EnhancedDateFormatter.adjustDisabledStates = function() {
setDisabledOrEnabled(["label_defaultDateFormat", "textbox_defaultDateFormat",
"checkbox_useCustomFormatForToday",
"checkbox_useCustomFormatForYesterday",
"checkbox_useCustomFormatForLastWeek"],
document.getElementById("checkbox_useCustomFormatsForDateColumn").checked |
document.getElementById("checkbox_useCustomFormatsForReceivedColumn").checked |
document.getElementById("checkbox_useCustomFormatsForMessagePane").checked);

setDisabledOrEnabled(["label_todayDateFormat", "textbox_todayDateFormat"],
(document.getElementById("checkbox_useCustomFormatsForDateColumn").checked |
document.getElementById("checkbox_useCustomFormatsForReceivedColumn").checked |
document.getElementById("checkbox_useCustomFormatsForMessagePane").checked) &
document.getElementById("checkbox_useCustomFormatForToday").checked)

setDisabledOrEnabled(["label_yesterdayDateFormat", "textbox_yesterdayDateFormat"],
(document.getElementById("checkbox_useCustomFormatsForDateColumn").checked |
document.getElementById("checkbox_useCustomFormatsForReceivedColumn").checked |
document.getElementById("checkbox_useCustomFormatsForMessagePane").checked) &
document.getElementById("checkbox_useCustomFormatForYesterday").checked)

setDisabledOrEnabled(["label_lastWeekDateFormat", "textbox_lastWeekDateFormat"],
(document.getElementById("checkbox_useCustomFormatsForDateColumn").checked |
document.getElementById("checkbox_useCustomFormatsForReceivedColumn").checked |
document.getElementById("checkbox_useCustomFormatsForMessagePane").checked) &
document.getElementById("checkbox_useCustomFormatForLastWeek").checked)

}


EnhancedDateFormatter.onPrefWindowLoad = function () {
EnhancedDateFormatter.adjustDisabledStates();
}


Loading

0 comments on commit cf6845f

Please sign in to comment.