gecko-dev/toolkit/components/extensions/ext-alarms.js
2015-08-14 17:57:34 -07:00

171 lines
4.0 KiB
JavaScript

const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
let {
EventManager,
ignoreEvent,
} = ExtensionUtils;
// WeakMap[Extension -> Set[Alarm]]
let alarmsMap = new WeakMap();
// WeakMap[Extension -> callback]
let alarmCallbacksMap = new WeakMap();
// Manages an alarm created by the extension (alarms API).
function Alarm(extension, name, alarmInfo)
{
this.extension = extension;
this.name = name;
this.when = alarmInfo.when;
this.delayInMinutes = alarmInfo.delayInMinutes;
this.periodInMinutes = alarmInfo.periodInMinutes;
this.canceled = false;
let delay, scheduledTime;
if (this.when) {
scheduledTime = this.when;
delay = this.when - Date.now();
} else {
delay = this.delayInMinutes * 60 * 1000;
scheduledTime = Date.now() + delay;
}
this.scheduledTime = scheduledTime;
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
timer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
this.timer = timer;
}
Alarm.prototype = {
clear() {
this.timer.cancel();
alarmsMap.get(this.extension).delete(this);
this.canceled = true;
},
observe(subject, topic, data) {
if (alarmCallbacksMap.has(this.extension)) {
alarmCallbacksMap.get(this.extension)(this);
}
if (this.canceled) {
return;
}
if (!this.periodInMinutes) {
this.clear();
return;
}
let delay = this.periodInMinutes * 60 * 1000;
this.scheduledTime = Date.now() + delay;
this.timer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
},
get data() {
return {
name: this.name,
scheduledTime: this.scheduledTime,
periodInMinutes: this.periodInMinutes,
};
},
};
extensions.on("startup", (type, extension) => {
alarmsMap.set(extension, new Set());
});
extensions.on("shutdown", (type, extension) => {
for (let alarm of alarmsMap.get(extension)) {
alarm.clear();
}
alarmsMap.delete(extension);
});
extensions.registerAPI((extension, context) => {
return {
alarms: {
create: function(...args) {
let name = "", alarmInfo;
if (args.length == 1) {
alarmInfo = args[0];
} else {
[name, alarmInfo] = args;
}
let alarm = new Alarm(extension, name, alarmInfo);
alarmsMap.get(extension).add(alarm);
},
get: function(args) {
let name = "", callback;
if (args.length == 1) {
callback = args[0];
} else {
[name, callback] = args;
}
for (let alarm of alarmsMap.get(extension)) {
if (alarm.name == name) {
runSafe(context, callback, alarm.data);
break;
}
}
},
getAll: function(callback) {
let alarms = alarmsMap.get(extension);
result = [ for (alarm of alarms) alarm.data ];
runSafe(context, callback, result);
},
clear: function(...args) {
let name = "", callback;
if (args.length == 1) {
callback = args[0];
} else {
[name, callback] = args;
}
let alarms = alarmsMap.get(extension);
let cleared = false;
for (let alarm of alarms) {
if (alarm.name == name) {
alarm.clear();
cleared = true;
break;
}
}
if (callback) {
runSafe(context, callback, cleared);
}
},
clearAll: function(callback) {
let alarms = alarmsMap.get(extension);
let cleared = false;
for (let alarm of alarms) {
alarm.clear();
cleared = true;
}
if (callback) {
runSafe(context, callback, cleared);
}
},
onAlarm: new EventManager(context, "alarms.onAlarm", fire => {
let callback = alarm => {
fire(alarm.data);
};
alarmCallbacksMap.set(extension, callback);
return () => {
alarmCallbacksMap.delete(extension);
};
}).api(),
},
};
});