-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
jgillula
committed
Jun 23, 2019
1 parent
9ad6ea2
commit cf6845f
Showing
12 changed files
with
1,198 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
|
||
|
Oops, something went wrong.