2011-07-03 14:05:40 -04:00
|
|
|
/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
2012-08-03 17:52:29 -04:00
|
|
|
/* for now, logging facilities (imported from logging.jsm) and Services are
|
|
|
|
automatically provided by this module */
|
2011-09-07 10:24:14 -04:00
|
|
|
var EXPORTED_SYMBOLS =
|
2012-09-03 18:25:29 -04:00
|
|
|
[ "firetray", "FIRETRAY_ID", "FIRETRAY_VERSION", "FIRETRAY_PREF_BRANCH",
|
|
|
|
"FIRETRAY_SPLASH_PAGE", "FIRETRAY_APPLICATION_ICON_TYPE_THEMED",
|
2012-04-07 17:06:54 -04:00
|
|
|
"FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM",
|
2012-09-07 11:20:38 -04:00
|
|
|
"FIRETRAY_NOTIFICATION_MESSAGE_COUNT",
|
2012-02-08 18:03:29 -05:00
|
|
|
"FIRETRAY_NOTIFICATION_NEWMAIL_ICON", "FIRETRAY_NOTIFICATION_CUSTOM_ICON",
|
2012-08-13 06:07:57 -04:00
|
|
|
"FIRETRAY_IM_STATUS_AVAILABLE", "FIRETRAY_IM_STATUS_AWAY",
|
|
|
|
"FIRETRAY_IM_STATUS_BUSY", "FIRETRAY_IM_STATUS_OFFLINE",
|
2012-09-06 13:07:22 -04:00
|
|
|
"FIRETRAY_ACCOUNT_SERVER_TYPE_IM",
|
2012-01-26 05:37:41 -05:00
|
|
|
"FIRETRAY_DELAY_BROWSER_STARTUP_MILLISECONDS",
|
2012-04-07 17:06:54 -04:00
|
|
|
"FIRETRAY_DELAY_NOWAIT_MILLISECONDS",
|
2012-03-20 17:06:19 -04:00
|
|
|
"FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS",
|
2012-09-02 19:38:04 -04:00
|
|
|
"FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD", "FIRETRAY_MESSAGE_COUNT_TYPE_NEW",
|
2013-03-10 15:51:33 -04:00
|
|
|
"FIRETRAY_APP_DB" ];
|
2011-07-03 14:05:40 -04:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
2011-07-12 19:23:58 -04:00
|
|
|
const Cu = Components.utils;
|
|
|
|
|
2011-08-07 21:37:50 -04:00
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
2011-12-14 16:00:01 -05:00
|
|
|
Cu.import("resource://firetray/logging.jsm");
|
2011-07-03 14:05:40 -04:00
|
|
|
|
2013-01-28 04:31:50 -05:00
|
|
|
const FIRETRAY_VERSION = "0.4.5"; // needed for sync call of onVersionChange() :(
|
2012-01-30 15:10:26 -05:00
|
|
|
const FIRETRAY_ID = "{9533f794-00b4-4354-aa15-c2bbda6989f8}";
|
2013-03-10 15:51:33 -04:00
|
|
|
const FIRETRAY_PREF_BRANCH = "extensions.firetray.";
|
2012-01-30 15:10:26 -05:00
|
|
|
const FIRETRAY_SPLASH_PAGE = "http://foudfou.github.com/FireTray/";
|
|
|
|
|
2012-08-03 09:53:36 -04:00
|
|
|
const FIRETRAY_APPLICATION_ICON_TYPE_THEMED = 0;
|
|
|
|
const FIRETRAY_APPLICATION_ICON_TYPE_CUSTOM = 1;
|
|
|
|
|
2012-09-07 11:20:38 -04:00
|
|
|
const FIRETRAY_MESSAGE_COUNT_TYPE_UNREAD = 0;
|
|
|
|
const FIRETRAY_MESSAGE_COUNT_TYPE_NEW = 1;
|
2012-03-13 07:51:40 -04:00
|
|
|
|
2012-09-07 11:20:38 -04:00
|
|
|
const FIRETRAY_NOTIFICATION_MESSAGE_COUNT = 0;
|
|
|
|
const FIRETRAY_NOTIFICATION_NEWMAIL_ICON = 1;
|
|
|
|
const FIRETRAY_NOTIFICATION_CUSTOM_ICON = 2;
|
2011-11-06 11:42:43 -05:00
|
|
|
|
2012-08-13 06:07:57 -04:00
|
|
|
const FIRETRAY_IM_STATUS_AVAILABLE = "user-available";
|
|
|
|
const FIRETRAY_IM_STATUS_AWAY = "user-away";
|
|
|
|
const FIRETRAY_IM_STATUS_BUSY = "user-busy";
|
|
|
|
const FIRETRAY_IM_STATUS_OFFLINE = "user-offline";
|
|
|
|
|
2012-09-06 13:07:22 -04:00
|
|
|
const FIRETRAY_ACCOUNT_SERVER_TYPE_IM = "im";
|
|
|
|
|
2012-01-26 05:37:41 -05:00
|
|
|
const FIRETRAY_DELAY_BROWSER_STARTUP_MILLISECONDS = 500;
|
|
|
|
const FIRETRAY_DELAY_NOWAIT_MILLISECONDS = 0;
|
2012-03-20 17:06:19 -04:00
|
|
|
const FIRETRAY_DELAY_PREF_CLEANING_MILLISECONDS = 15*60*1000;
|
2012-01-14 19:02:00 -05:00
|
|
|
|
2013-03-10 15:51:33 -04:00
|
|
|
const FIRETRAY_APP_DB = {
|
|
|
|
|
|
|
|
firefox: {
|
|
|
|
id: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
|
|
|
|
mainXUL: "chrome://browser/content/browser.xul"
|
|
|
|
},
|
|
|
|
|
|
|
|
thunderbird: {
|
|
|
|
id: "{3550f703-e582-4d05-9a08-453d09bdfdc6}",
|
|
|
|
mainXUL: "chrome://messenger/content/msgAccountCentral.xul"
|
|
|
|
},
|
|
|
|
|
|
|
|
seamonkey: {
|
|
|
|
id: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}",
|
|
|
|
mainXUL: null
|
|
|
|
},
|
|
|
|
|
|
|
|
songbird: {
|
|
|
|
id: "songbird@songbirdnest.com",
|
|
|
|
mainXUL: null
|
|
|
|
},
|
|
|
|
|
|
|
|
sunbird: {
|
|
|
|
id: "718e30fb-e89b-41dd-9da7-e25a45638b28}",
|
|
|
|
mainXUL: null
|
|
|
|
},
|
|
|
|
|
|
|
|
chatzilla: {
|
|
|
|
id: "{59c81df5-4b7a-477b-912d-4e0fdf64e5f2}",
|
|
|
|
mainXUL: null
|
2013-03-11 11:03:49 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
zotero: {
|
|
|
|
id: "zotero@chnm.gmu.edu",
|
|
|
|
mainXUL: null
|
2013-03-10 15:51:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2012-03-30 17:20:47 -04:00
|
|
|
|
2011-07-03 14:05:40 -04:00
|
|
|
/**
|
2011-09-24 06:00:31 -04:00
|
|
|
* firetray namespace.
|
2011-07-03 14:05:40 -04:00
|
|
|
*/
|
2011-09-24 06:00:31 -04:00
|
|
|
if ("undefined" == typeof(firetray)) {
|
|
|
|
var firetray = {};
|
2011-07-03 14:05:40 -04:00
|
|
|
};
|
|
|
|
|
2012-09-04 11:48:54 -04:00
|
|
|
let log = firetray.Logging.getLogger("firetray.commons");
|
2012-09-02 19:38:04 -04:00
|
|
|
|
2011-09-24 06:00:31 -04:00
|
|
|
firetray.Utils = {
|
2012-08-03 09:53:36 -04:00
|
|
|
prefService: Services.prefs.getBranch(FIRETRAY_PREF_BRANCH),
|
2011-09-24 06:00:31 -04:00
|
|
|
strings: Services.strings.createBundle("chrome://firetray/locale/overlay.properties"),
|
2011-09-07 18:55:34 -04:00
|
|
|
|
2012-08-03 17:52:29 -04:00
|
|
|
addObservers: function(handler, topics){
|
|
|
|
topics.forEach(function(topic){
|
2012-09-06 10:07:12 -04:00
|
|
|
if (this.observedTopics[topic]) {
|
|
|
|
log.warn(topic+" already registred for "+handler);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-08-03 17:52:29 -04:00
|
|
|
Services.obs.addObserver(this, topic, false);
|
|
|
|
this.observedTopics[topic] = true;
|
2012-09-03 18:25:29 -04:00
|
|
|
log.debug("registred "+topic+" for "+handler);
|
2012-08-03 17:52:29 -04:00
|
|
|
}, handler);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeObservers: function(handler, topics) {
|
|
|
|
topics.forEach(function(topic){
|
|
|
|
Services.obs.removeObserver(this, topic);
|
|
|
|
delete this.observedTopics[topic];
|
|
|
|
}, handler);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeAllObservers: function(handler) {
|
|
|
|
for (let topic in handler.observedTopics)
|
|
|
|
Services.obs.removeObserver(handler, topic);
|
|
|
|
handler.observedTopics = {};
|
|
|
|
},
|
|
|
|
|
2011-10-29 16:27:55 -04:00
|
|
|
getObjPref: function(prefStr) {
|
|
|
|
try {
|
|
|
|
var objPref = JSON.parse(
|
|
|
|
firetray.Utils.prefService.getCharPref(prefStr));
|
|
|
|
} catch (x) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.error(x);
|
2011-10-29 16:27:55 -04:00
|
|
|
}
|
|
|
|
return objPref;
|
|
|
|
},
|
|
|
|
setObjPref: function(prefStr, obj) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.debug(obj);
|
2011-10-29 16:27:55 -04:00
|
|
|
try {
|
|
|
|
firetray.Utils.prefService.setCharPref(prefStr, JSON.stringify(obj));
|
|
|
|
} catch (x) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.error(x);
|
2011-10-29 16:27:55 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
getArrayPref: function(prefStr) {
|
|
|
|
let arrayPref = this.getObjPref(prefStr);
|
2012-03-08 16:04:16 -05:00
|
|
|
if (!firetray.js.isArray(arrayPref)) throw new TypeError();
|
2011-10-29 16:27:55 -04:00
|
|
|
return arrayPref;
|
|
|
|
},
|
|
|
|
setArrayPref: function(prefStr, aArray) {
|
2012-03-08 16:04:16 -05:00
|
|
|
if (!firetray.js.isArray(aArray)) throw new TypeError();
|
2011-10-29 16:27:55 -04:00
|
|
|
this.setObjPref(prefStr, aArray);
|
|
|
|
},
|
|
|
|
|
2011-09-26 04:02:51 -04:00
|
|
|
QueryInterfaces: function(obj) {
|
2012-01-02 12:35:02 -05:00
|
|
|
for each (i in Components.interfaces)
|
2011-09-26 04:02:51 -04:00
|
|
|
try {
|
2012-09-02 19:38:04 -04:00
|
|
|
if (obj instanceof i) log.debug (i);
|
2012-01-02 12:35:02 -05:00
|
|
|
} catch(x) {}
|
2011-09-26 04:02:51 -04:00
|
|
|
},
|
|
|
|
|
2011-09-07 18:55:34 -04:00
|
|
|
// adapted from http://forums.mozillazine.org/viewtopic.php?p=921150#921150
|
|
|
|
chromeToPath: function(aPath) {
|
|
|
|
if (!aPath || !(/^chrome:/.test(aPath)))
|
|
|
|
return null; // not a chrome url
|
|
|
|
|
|
|
|
let uri = Services.io.newURI(aPath, "UTF-8", null);
|
|
|
|
let registeryValue = Cc['@mozilla.org/chrome/chrome-registry;1']
|
|
|
|
.getService(Ci.nsIChromeRegistry)
|
|
|
|
.convertChromeURL(uri).spec;
|
2012-09-02 19:38:04 -04:00
|
|
|
log.debug(registeryValue);
|
2011-09-07 18:55:34 -04:00
|
|
|
|
|
|
|
if (/^file:/.test(registeryValue))
|
|
|
|
registeryValue = this._urlToPath(registeryValue);
|
|
|
|
else
|
|
|
|
registeryValue = this._urlToPath("file://"+registeryValue);
|
|
|
|
|
|
|
|
return registeryValue;
|
|
|
|
},
|
|
|
|
|
|
|
|
_urlToPath: function (aPath) {
|
|
|
|
if (!aPath || !/^file:/.test(aPath))
|
|
|
|
return null;
|
|
|
|
|
|
|
|
let protocolHandler = Cc["@mozilla.org/network/protocol;1?name=file"]
|
|
|
|
.createInstance(Ci.nsIFileProtocolHandler);
|
|
|
|
return protocolHandler.getFileFromURLSpec(aPath).path;
|
2011-11-01 20:48:41 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
dumpObj: function(obj) {
|
|
|
|
let str = "";
|
|
|
|
for(i in obj) {
|
|
|
|
try {
|
|
|
|
str += "obj["+i+"]: " + obj[i] + "\n";
|
|
|
|
} catch(e) {
|
|
|
|
str += "obj["+i+"]: Unavailable\n";
|
|
|
|
}
|
|
|
|
}
|
2013-04-07 10:45:17 -04:00
|
|
|
log.info(str);
|
2011-11-02 20:14:47 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
_nsResolver: function(prefix) {
|
|
|
|
var ns = {
|
|
|
|
xul: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
|
|
|
};
|
|
|
|
return ns[prefix] || null;
|
|
|
|
},
|
|
|
|
|
|
|
|
// adapted from http://code.google.com/p/jslibs/wiki/InternalTipsAndTricks
|
|
|
|
XPath: function(ref, xpath) {
|
|
|
|
var doc = ref.ownerDocument || ref;
|
|
|
|
|
|
|
|
const XPathResult = Ci.nsIDOMXPathResult;
|
|
|
|
try {
|
|
|
|
let that = this;
|
|
|
|
var result = doc.evaluate(xpath, ref, that._nsResolver,
|
|
|
|
XPathResult.ANY_TYPE, null);
|
|
|
|
} catch (x) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.error(x);
|
2011-11-02 20:14:47 -04:00
|
|
|
}
|
2012-09-02 19:38:04 -04:00
|
|
|
log.debug("XPathResult="+result.resultType);
|
2011-11-02 20:14:47 -04:00
|
|
|
|
|
|
|
switch (result.resultType) {
|
|
|
|
case XPathResult.NUMBER_TYPE:
|
|
|
|
return result.numberValue;
|
|
|
|
case XPathResult.BOOLEAN_TYPE:
|
|
|
|
return result.booleanValue;
|
|
|
|
case XPathResult.STRING_TYPE:
|
|
|
|
return result.stringValue;
|
2012-09-11 17:53:07 -04:00
|
|
|
} // else XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
|
2011-11-02 20:14:47 -04:00
|
|
|
|
|
|
|
var list = [];
|
|
|
|
try {
|
|
|
|
for (let node = result.iterateNext(); node; node = result.iterateNext()) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.debug("node="+node.nodeName);
|
2011-11-02 20:14:47 -04:00
|
|
|
switch (node.nodeType) {
|
|
|
|
case node.ATTRIBUTE_NODE:
|
|
|
|
list.push(node.value);
|
|
|
|
break;
|
|
|
|
case node.TEXT_NODE:
|
|
|
|
list.push(node.data);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
list.push(node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (x) {
|
2012-09-02 19:38:04 -04:00
|
|
|
log.error(x);
|
2011-11-02 20:14:47 -04:00
|
|
|
}
|
|
|
|
|
2012-09-11 17:53:07 -04:00
|
|
|
log.debug("len="+list.length);
|
2011-11-02 20:14:47 -04:00
|
|
|
return list;
|
2012-01-15 14:47:47 -05:00
|
|
|
},
|
|
|
|
|
2013-03-10 12:29:32 -04:00
|
|
|
/*
|
|
|
|
* keep a long-living reference to the returned timer, if you don't want to
|
|
|
|
* see it GC'ed ! see
|
|
|
|
* http://www.joshmatthews.net/blog/2011/03/nsitimer-anti-pattern/
|
|
|
|
*/
|
2012-12-13 13:14:45 -05:00
|
|
|
timer: function(delay, timerType, callback) {
|
2012-01-26 05:37:41 -05:00
|
|
|
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
|
|
|
timer.initWithCallback({ notify: callback },
|
|
|
|
delay, timerType);
|
2012-03-20 17:06:19 -04:00
|
|
|
return timer;
|
2011-09-07 18:55:34 -04:00
|
|
|
}
|
|
|
|
|
2011-07-03 14:05:40 -04:00
|
|
|
};
|
2011-10-03 04:39:25 -04:00
|
|
|
|
2012-01-15 15:26:46 -05:00
|
|
|
////////////////////////// more fundamental helpers //////////////////////////
|
|
|
|
|
2012-03-08 16:04:16 -05:00
|
|
|
firetray.js = {
|
|
|
|
// http://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript
|
|
|
|
isArray: function(o) {
|
|
|
|
return this.getType(o) === '[object Array]';
|
|
|
|
},
|
|
|
|
getType: function(thing) {
|
2012-01-07 10:06:10 -05:00
|
|
|
if(thing === null) return "[object Null]"; // special case
|
|
|
|
return Object.prototype.toString.call(thing);
|
2012-03-08 16:04:16 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object-from-json
|
|
|
|
isEmpty: function(obj) {
|
|
|
|
for(var prop in obj) {
|
|
|
|
if(obj.hasOwnProperty(prop))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
// values of different ctypes objects can never be compared. See:
|
|
|
|
// https://developer.mozilla.org/en/js-ctypes/Using_js-ctypes/Working_with_data#Quirks_in_equality
|
|
|
|
strEquals: function(obj1, obj2) {
|
|
|
|
return obj1.toString() === obj2.toString();
|
|
|
|
}
|
|
|
|
};
|
2011-11-02 21:51:43 -04:00
|
|
|
|
|
|
|
// http://stackoverflow.com/questions/18912/how-to-find-keys-of-a-hash
|
|
|
|
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
|
|
|
|
if(!Object.keys) Object.keys = function(o){
|
|
|
|
if (o !== Object(o))
|
|
|
|
throw new TypeError('Object.keys called on non-object');
|
|
|
|
var ret=[],p;
|
|
|
|
for(p in o) if(Object.prototype.hasOwnProperty.call(o,p)) ret.push(p);
|
|
|
|
return ret;
|
|
|
|
};
|
2011-12-10 22:45:44 -05:00
|
|
|
|
2012-03-13 07:51:40 -04:00
|
|
|
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim
|
|
|
|
if(!String.prototype.trim) {
|
|
|
|
String.prototype.trim = function () {
|
|
|
|
return this.replace(/^\s+|\s+$/g,'');
|
|
|
|
};
|
|
|
|
}
|